You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中实现基于内容自适应的双文本行布局以满足三种场景需求

Flutter中实现基于内容自适应的双文本行布局以满足三种场景需求

嘿,我明白你现在卡在哪了——默认的Flexible用flex:1会强制两个文本平分空间,完全没法适配一短一长的情况,导致长文本被硬生生砍成一半,体验特别别扭。我来给你一个能同时满足三个场景的解决方案,核心是先动态计算文本的实际宽度,再根据宽度关系调整布局逻辑。

你当前的代码里,两个Flexible都用了默认的flex:1,这会让Row不管文本内容长短,都把可用空间1:1分配给它们。哪怕第一个文本只有几个字,它也会占走一半的宽度,剩下的一半给第二个文本,导致长文本没法利用多余的空间展示更多内容。

要实现你要的三种场景,我们需要先知道两个文本在不限制宽度时的实际长度,再结合可用空间来动态调整布局:

  1. 计算文本的实际宽度:用TextPainter模拟文本绘制,获取它的无约束宽度
  2. 分情况处理布局:
    • 当两个文本总长度不超过可用宽度:直接把两个文本放在Row里,紧挨着就行
    • 当两个文本各自的长度都超过可用宽度的一半:用两个Flexible平分空间,各自省略超出部分
    • 其他情况(一短一长):短的文本直接用Text占据自身宽度,长的文本用Expanded占据剩余所有空间,超出部分省略

下面是完整的实现代码:

@override
Widget build(BuildContext context) {
  final first = 'First text is very long and long';
  final second = 'Second text is also long';

  // 计算文本在无约束情况下的真实宽度
  double calculateTextWidth(String text, TextStyle style) {
    final textPainter = TextPainter(
      text: TextSpan(text: text, style: style),
      maxLines: 1,
      textDirection: TextDirection.ltr,
    )..layout(minWidth: 0, maxWidth: double.infinity);
    return textPainter.width;
  }

  return Scaffold(
    appBar: AppBar(
      title: const Text('Flexible Page'),
    ),
    body: Column(
      children: [
        Container(
          color: Colors.grey.shade300,
          width: 300,
          child: LayoutBuilder(
            builder: (context, constraints) {
              final availableWidth = constraints.maxWidth;
              // 获取当前文本的默认样式,有自定义样式的话记得传进来
              final textStyle = DefaultTextStyle.of(context).style;
              final firstWidth = calculateTextWidth(first, textStyle);
              final secondWidth = calculateTextWidth(second, textStyle);
              final totalWidth = firstWidth + secondWidth;
              final halfWidth = availableWidth / 2;

              if (totalWidth <= availableWidth) {
                // 场景2:两个文本都短,总宽度不超可用空间,直接紧挨着
                return Row(
                  children: [
                    Text(first),
                    Text(second),
                  ],
                );
              } else if (firstWidth > halfWidth && secondWidth > halfWidth) {
                // 场景1:两个文本都很长,各自都超一半宽度,平分空间
                return Row(
                  children: [
                    Flexible(
                      child: Text(
                        first,
                        overflow: TextOverflow.ellipsis,
                        maxLines: 1,
                      ),
                    ),
                    Flexible(
                      child: Text(
                        second,
                        overflow: TextOverflow.ellipsis,
                        maxLines: 1,
                      ),
                    ),
                  ],
                );
              } else {
                // 场景3:一短一长,短的占自身宽度,长的占剩余所有空间
                return Row(
                  children: [
                    firstWidth <= secondWidth
                        ? Text(first)
                        : Expanded(
                            child: Text(
                              first,
                              overflow: TextOverflow.ellipsis,
                              maxLines: 1,
                            ),
                          ),
                    secondWidth <= firstWidth
                        ? Text(second)
                        : Expanded(
                            child: Text(
                              second,
                              overflow: TextOverflow.ellipsis,
                              maxLines: 1,
                            ),
                          ),
                  ],
                );
              }
            },
          ),
        ),
      ],
    ),
  );
}

再给你补充几个小细节:

  • 如果你的文本用了自定义样式,一定要把样式传给calculateTextWidth方法,不然计算出的宽度会和实际显示的不一致
  • 给Text加上maxLines:1,确保文本不会换行,和overflow: TextOverflow.ellipsis配合更稳妥
  • 这个方案是完全动态的,不管你怎么修改文本内容,布局都会自动适配对应的场景

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 13:23:00