Flutter中如何避免Row水平溢出并显示省略号
Flutter Row溢出时用省略号替代溢出内容
问题描述
我有一个包含多个子组件的Row,当屏幕宽度较小时会出现水平溢出报错。我不想使用Wrap组件让溢出的子项换行显示,而是希望溢出部分直接替换成省略号(...)或者自定义组件,比如当第5个Text("this is test 5")开始引发溢出时,用省略号替代后续所有内容。
期望效果

当前问题
屏幕宽度不足时,Row会出现水平溢出报错,效果如下:
已尝试代码
return const MaterialApp( home: Scaffold( body: Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("this is test 1"), Icon( Icons.circle, size: 5, ), Text("this is test 2"), Icon( Icons.circle, size: 5, ), Text("this is test 3"), Icon( Icons.circle, size: 5, ), Text("this is test 4"), Icon( Icons.circle, size: 5, ), Text("this is test 5"), Icon( Icons.circle, size: 5, ), Text("this is test 6"), Icon( Icons.circle, size: 5, ), ], ), ), ), );
解决方案
可以通过LayoutBuilder获取父容器的可用宽度,逐个计算子组件的宽度,当累计宽度加上省略号宽度超过可用空间时,停止添加后续子组件并插入省略号。示例代码如下:
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( home: Scaffold( body: Center( child: ResponsiveRowWithEllipsis(), ), ), ); } } class ResponsiveRowWithEllipsis extends StatelessWidget { const ResponsiveRowWithEllipsis({super.key}); @override Widget build(BuildContext context) { // 定义所有需要展示的子组件 final List<Widget> originalChildren = [ const Text("this is test 1"), const Icon(Icons.circle, size: 5), const Text("this is test 2"), const Icon(Icons.circle, size: 5), const Text("this is test 3"), const Icon(Icons.circle, size: 5), const Text("this is test 4"), const Icon(Icons.circle, size: 5), const Text("this is test 5"), const Icon(Icons.circle, size: 5), const Text("this is test 6"), const Icon(Icons.circle, size: 5), ]; return LayoutBuilder( builder: (context, constraints) { double totalUsedWidth = 0; final List<Widget> displayChildren = []; final textScaleFactor = MediaQuery.of(context).textScaleFactor; // 计算省略号的宽度 final ellipsisPainter = TextPainter( text: const TextSpan(text: "..."), maxLines: 1, textScaleFactor: textScaleFactor, textDirection: TextDirection.ltr, )..layout(); final ellipsisWidth = ellipsisPainter.width; // 遍历子组件,筛选能显示的部分 for (final child in originalChildren) { double childWidth = 0; // 计算不同类型子组件的宽度 if (child is Text) { final textPainter = TextPainter( text: TextSpan(text: child.data, style: child.style), maxLines: 1, textScaleFactor: textScaleFactor, textDirection: TextDirection.ltr, )..layout(); childWidth = textPainter.width; } else if (child is Icon) { childWidth = child.size; } // 预留子组件间距和省略号宽度,判断是否还能容纳当前子组件 const double itemSpacing = 8; // 子组件间的间距,可自行调整 if (totalUsedWidth + childWidth + itemSpacing + ellipsisWidth > constraints.maxWidth) { displayChildren.add(const Text("...")); break; } displayChildren.add(child); totalUsedWidth += childWidth + itemSpacing; } return Row( mainAxisAlignment: MainAxisAlignment.center, children: displayChildren, ); }, ); } }
代码说明
- 使用
LayoutBuilder获取当前Row的可用宽度,确保计算基于实际可用空间。 - 逐个计算每个子组件的宽度,针对Text和Icon组件做了专门的宽度计算逻辑,其他类型组件可自行扩展。
- 预留了子组件间的间距和省略号的宽度,当剩余空间不足以容纳当前子组件+省略号时,就停止添加后续子组件,插入省略号。
- 最终将筛选后的子组件和省略号放入Row中,实现不换行的溢出省略效果。
内容的提问来源于stack exchange,提问作者Bart Van de Veire
相关产品推荐
相关产品推荐

