为 Row 中的所有子级设置相同的大小
Posted
技术标签:
【中文标题】为 Row 中的所有子级设置相同的大小【英文标题】:Set equal size to all children in Row 【发布时间】:2020-03-23 00:00:42 【问题描述】:我有一个像这样有 2 个孩子的 Row:
----------------------
| wide child1 | child2 |
----------------------
有没有办法让每个单元格的大小相等,从而使每个单元格的宽度等于最宽单元格的宽度?像这样:
--------------------------
| wide child1 | child2 |
--------------------------
所以整个 Row 的宽度将占用 biggestCellWidth * numOfChildren
。
我无法使用内置小部件实现此行为,并尝试实现 MultiChildLayoutDelegate
但它也不起作用,因为我无法测量儿童。
更新:
// in build function
Container(
height: 48,
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: BorderRadius.circular(16),
color: Theme.of(context).colorScheme.primary,
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
// this widgets should be equal in width
_buildButton(
text: "Review",
onTap: _onReviewTap,
),
_buildButton(
text: "Buy",
onTap: _onBuyTap,
),
],
),
),
);
Widget _buildButton(
@required String text,
@required Function onTap,
@required EdgeInsets padding,
)
return InkWell(
onTap: onTap,
child: Center(
child: Text(
text,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
);
【问题讨论】:
你想这样布局文本小部件吗? 【参考方案1】:将你的 child1 和 child2 包裹在 Expanded 中,
Row(
children: <Widget>[
Expanded(
child: Container(
color: Colors.amber,
height: 100,
),
),
Expanded(
child: Container(
color: Colors.amber,
height: 100,
),
),
【讨论】:
如果我不明确指定行的宽度,它就不起作用。我不想这样做,因为所有孩子都是Text
小部件,它们的宽度可能因语言而异。
或者如果你想使用Flexible
而不是Expanded
,那么别忘了使用fit:FlexFit.tight
。给两个孩子相同的大小。
@frozzyk 分享你的鳕鱼片
我们也可以将“flex”设置为Expanded widget的属性,用于调整两个Expanded widget的宽度比例。谢谢亲爱的,它有效:)【参考方案2】:
我想你想要的是Table?例如:
Table(
columnWidths: const
0: FlexColumnWidth(),
1: FlexColumnWidth(),
,
children: [
TableRow(
children: [
Text(
"Review",
),
Text(
"Buy",
),
]
),
],
)
【讨论】:
看起来像我需要的。我稍后会试试这个。谢谢【参考方案3】:您提到您所有的孩子都是Text
小部件。我们可以渲染文本以了解它们的大小 (reference),选择最大宽度并使用 MultiChildLayoutDelegate
进行布局。这有点hacky,但会起作用:
class _HomePageState extends State<HomePage>
@override
Widget build(BuildContext context)
final texts = [
Text('loooooooooooong text'),
Text('short one'),
Text('one more'),
];
final children = <Widget>[
for (int i = 0; i < texts.length; i++)
LayoutId(
id: '$_kLayoutKey$i',
child: Container(
color: Color.fromARGB(255, Random().nextInt(255), Random().nextInt(255), Random().nextInt(255)),
child: texts[i],
),
),
];
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: CustomMultiChildLayout(
delegate: _CircularLayoutDelegate(texts, 14),
children: children,
)
),
);
const String _kLayoutKey = 'test';
class _CircularLayoutDelegate extends MultiChildLayoutDelegate
_CircularLayoutDelegate(this.texts, this.fontSize);
final double fontSize;
final List<Text> texts;
double _calcTextWidth(BoxConstraints constraints, Text textWidget)
RenderParagraph renderParagraph = RenderParagraph(
TextSpan(
text: textWidget.data,
style: TextStyle(
fontSize: fontSize,
),
),
textDirection: TextDirection.ltr,
maxLines: 1,
);
renderParagraph.layout(constraints);
return renderParagraph.getMinIntrinsicWidth(fontSize).ceilToDouble();
@override
void performLayout(Size size)
final textSizes = [
for (final text in texts)
_calcTextWidth(BoxConstraints.loose(size), text),
];
final maxWidth = textSizes.fold<double>(0, (p, v)
final textWidth = v;
return textWidth > p ? textWidth : p;
);
final textConstraint = BoxConstraints(
maxWidth: maxWidth,
minWidth: maxWidth,
maxHeight: size.height,
);
for (int i = 0; i < texts.length; i++)
final String childId = '$_kLayoutKey$i';
if (hasChild(childId))
layoutChild('$_kLayoutKey$i', textConstraint);
positionChild(
childId,
Offset(maxWidth * i, 0),
);
@override
bool shouldRelayout(_CircularLayoutDelegate oldDelegate) => oldDelegate.texts != texts;
【讨论】:
看起来像我想要的,谢谢!可惜在颤振中做起来很棘手。 小部件不是文本怎么办? @frozzyk 我猜你必须走得更低并使用渲染对象(例如,像从 MultiChildRenderObjectWidget 扩展的Flex
类),这会更难。您可以在 performLayout
方法中访问子渲染框并了解它们的大小。【参考方案4】:
您可以使用相同的弹性编号将每个小部件包装在 Flexible 中
【讨论】:
在我的情况下它不起作用,因为父Row
没有固定大小。以上是关于为 Row 中的所有子级设置相同的大小的主要内容,如果未能解决你的问题,请参考以下文章
在 Plotly Express 散点图中将所有标记设置为相同的固定大小