为 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 中的所有子级设置相同的大小的主要内容,如果未能解决你的问题,请参考以下文章

为没有for循环的数据表中的所有行设置值

在 Plotly Express 散点图中将所有标记设置为相同的固定大小

根据父级大小按比例缩小小部件中的所有子级

MariaDB 在一个命令中将所有表的 row_format 设置为动态

根据显示弹性框中的子级设置父级高度/宽度

word文档样式设置图文教程