如何通过读取 child 约束使一行的 children 具有相同的高度

How to make children of a Row have the same height by reading child constraints

我有一个带有委托的 SliverList,每个项目的 returns 行。设计需要这样的结果:

两个children是Text和Image。图像 fir 是 BoxFit.cover,我正在使用 Flexible 为它们提供所需的宽度比。仅当高度大于或等于宽度边界(以使其至少保持正方形)时,我才需要图像边界高度与文本高度相匹配。

第一个解决方案是使用LayoutBuilder读取图像宽度的约束,并将图像放在一个ConstrainedBox中,minHeight为LayoutBuilder->constraints->maxWidth。

LayoutBuilder(
  builder: (context, constraints) => ConstrainedBox(
    constraints: BoxConstraints(
        minHeight: constraints.maxWidth,
        maxHeight: constraints.maxWidth),
    child: CachedNetworkImage(
        imageUrl: "https://via.placeholder.com/400x300",
        fit: BoxFit.cover,
      ),
  ),
)

一切都很好,直到文本长于图像宽度,此时图像仍然是正方形并且不会拉伸到完整的行高:

第二种解决方案 是将 Row 包装在 IntrinsicHeight 小部件中。但这意味着我无法使用其中的 LayoutBuilder。所以我删除了 Layout 构建器,现在我无法访问约束来设置 Image minHeight。图像拉伸得很好,可以填满整个行高。直到文字太短,导致图片高度低于宽度:

如何构建此设计以响应可变文本高度?

这可以巧妙地使用 Stack 代替,因为 Stack 的大小将匹配其未定位的子项,因此它会自动匹配您的 Text 小部件。然后使用 Positioned 小部件显示图像 - 将其 topbottom 设置为 0 使其垂直拉伸,设置 right: 0 使其对齐, 并给它一个固定的宽度。

示例源代码:

class Test extends StatelessWidget {
  const Test({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Flutter Demo")),
      body: ListView(
        children: [
          for (int i = 8; i < 40; i += 6)
            Stack(
              children: [
                Padding(
                  padding: EdgeInsets.only(right: 100),
                  child: Text("Lorem ipsum " * i),
                ),
                Positioned(
                  top: 0,
                  bottom: 0,
                  right: 0,
                  width: 100,
                  child: Container(color: Colors.primaries[i % 10]),
                ),
              ],
            ),
        ],
      ),
    );
  }
}

更新:

您在评论中提到,您希望强制执行“最低身高”。您可以在 Stack 中轻松做到这一点,方法是放置一个不可见的 SizedBox,例如:

Stack(
  children: [
    Padding(
      padding: EdgeInsets.only(right: 100),
      child: Text("Lorem ipsum " * i),
    ),
    SizedBox(height: 100), // this forces minimum height
    Positioned(
      top: 0,
      bottom: 0,
      right: 0,
      width: 100,
      child: Container(color: Colors.primaries[i % 10]),
    ),
  ],
),

结果:

所以我采用了答案 1 并使其具有响应性和文本方向感知能力(对于 RTL 语言)。这是最终的解决方案:

Stack(
  children: [
    Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Flexible(flex: 3, child: Text(("Hello There\n" * 10))),
        const Flexible(
          flex: 1,
          child: AspectRatio(
            aspectRatio: 1,
          ),
        )
      ],
    ),
    Positioned.fill(
      child: FractionallySizedBox(
        widthFactor: 0.25,
        alignment: AlignmentDirectional.topEnd,
        child: Image.network(
          'https://via.placeholder.com/600/92c952',
          fit: BoxFit.cover,
          // height: double.infinity,
        ),
      ),
    ),
  ],
)

只需用 IntrinsicHeight 包裹行

  
IntrinsicHeight(
  child: Row(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [...]
  )
)