如何通过读取 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
小部件显示图像 - 将其 top
和 bottom
设置为 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: [...]
)
)
我有一个带有委托的 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
小部件显示图像 - 将其 top
和 bottom
设置为 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: [...] ) )