Flutter - 如何在 Row 中放置两个 Columns,一个是扩展的,另一个适应其内容文本?

6
有没有一种方法可以使用Flutter实现此布局?在一行中,一个Column是扩展的,另一个Column则缩小以适应其中的文本。
我来自网页开发背景,我知道可以使用Flex-grow和Flex-shring以及whitespace:nowrap来实现它。
我想实现这个布局。

I would like to achieve this layout

但在Flutter中,我尝试了:
  1. 这将给我两个相等宽度的列:
Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Expanded(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisSize: MainAxisSize.min,
            children: [Text('Monthly Membership'), Text('Subscription')],
          ),
        ),
        Flexible(
          fit: FlexFit.tight,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(
                '+100',
                maxLines: 1,
                softWrap: false,
                overflow: TextOverflow.fade,
              ),
              Text(
                '18 Sept 2021',
                maxLines: 1,
                softWrap: false,
                overflow: TextOverflow.fade,
              ),
            ],
          ),
        ),
      ],
    );

这将会出现一个错误。

RenderBox没有被布局:RenderFlex#3024f relayoutBoundary=up1 需要绘制,需要更新合成位

Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Expanded(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisSize: MainAxisSize.min,
            children: [Text('Monthly Membership'), Text('Subscription')],
          ),
        ),
        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              '+100',
              maxLines: 1,
              softWrap: false,
              overflow: TextOverflow.fade,
            ),
            Text(
              '18 Sept 2021',
              maxLines: 1,
              softWrap: false,
              overflow: TextOverflow.fade,
            ),
          ],
        ),
      ],
    );

你在Column里使用了这一行吗? - Yeasin Sheikh
是的,该行也位于页面的一个较大列内。 - Edward Yuan
2个回答

5
您的第二次尝试失败了,因为CrossAxisAlignment.stretch会占用所有可用的水平空间,但是一个Row会给它的子控件一个无界限制的宽度约束。这将强制该列具有无限宽度,这是不可能的。有两个选项可以解决这个问题:
  1. 使用其他crossAxisAlignment

这将使Column的每个子元素都占用其需要的空间。根据您的图片,您可能想要CrossAxisAlignment.center,它将使该列的子元素居中对齐。该列的宽度将基于两个Text小部件中较大的一个。

        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          // ...
  1. 使用IntrinsicWidth

IntrinsicWidth会测量Column想要的宽度,然后将其设置为该宽度。这将在第二次布局中给Column一个紧密的宽度约束,使得CrossAxisAlignment.stretch按预期工作。

        IntrinsicWidth(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            // ...

两种选项都会使用不受限制的宽度来布局第二列,这意味着如果您有非常长的文本,可能会使第一列非常小。如果您想限制列的宽度,可以向任一解决方案添加ConstrainedBox


对于这个简单的UI,不适合使用“Intrinsic”小部件,因为它相对昂贵,会在最终布局阶段之前添加一次推测性布局传递。尽可能避免使用它。在最坏的情况下,该小部件可能导致树深度为O(N²)的布局。我和@Yeasin已经提到了更方便的解决方法。 - Jahidul Islam
我看这个Intrinsic选项很好用,@JahidulIslam你是说使用这个选项会有性能问题吗? - Edward Yuan
@edward 没错,这里存在性能问题。 - Jahidul Islam

3

你的代码片段运行良好,只是缺少对齐。
关于您想要的用户界面,您只需要设置对齐方式。

 Card(
            color: Colors.grey,
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Expanded(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisSize: MainAxisSize.min,
                      children: const [
                        Text('Monthly Membership'),
                        SizedBox(height: 10),
                        Text('Subscription'),
                      ],
                    ),
                  ),
                ),
                Flexible(
                  fit: FlexFit.tight,
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      crossAxisAlignment: CrossAxisAlignment.end,
                      mainAxisSize: MainAxisSize.min,
                      children: const [
                        Text(
                          '+100',
                          maxLines: 1,
                          softWrap: false,
                          overflow: TextOverflow.fade,
                        ),
                        SizedBox(height: 10),
                        Text(
                          '18 Sept 2021',
                          maxLines: 1,
                          softWrap: false,
                          overflow: TextOverflow.fade,
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
    

enter image description here


不完全是我要找的,如果您在“月度会员资格”区域添加更多文本,它将不会超过50%的标记。我希望左侧文本可以扩展到右侧部分的所有等待。 - Edward Yuan
在这种情况下,您可以从第二个“Column”中删除“Flexible”。 - Yeasin Sheikh
如果没有第二个“Flexible”,那么它将是我的尝试#2,会出现“NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE”的错误。 - Edward Yuan
你能把父级信息包含进去吗?我没有像你提到的那样出现错误。 - Yeasin Sheikh
它位于主屏幕的一个选项卡中,完整路径为:Scaffold -> IndexedStack -> Scaffold -> SingleChildScrollView -> Column -> Padding -> Container ->(行和两个列)。 - Edward Yuan
在列之前提供固定高度的情况下尝试。 - Yeasin Sheikh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接