Flutter如何实现多行文本溢出后将‘more’紧跟在省略号后?
多行文本溢出后让“more”紧跟省略号的实现方案
问题复盘
要实现多行文本溢出时显示省略号,还得让“more”紧跟在省略号后面。之前试了俩方案都不行:
- 单行的时候效果正常,但多行时“more”和主文本垂直对齐,完全不是想要的样子;
- 用
RichText组件也没搞定。
可行解决方案:自定义溢出文本组件
用LayoutBuilder结合TextPainter来动态计算文本是否溢出,然后拼接截断后的文本、省略号和“more”,就能实现预期效果。
完整代码示例
import 'package:flutter/material.dart'; class OverflowTextWithMore extends StatelessWidget { final String text; final String moreText; final TextStyle? textStyle; final TextStyle? moreStyle; final int maxLines; final double textScaleFactor; const OverflowTextWithMore({ super.key, required this.text, required this.moreText, this.textStyle, this.moreStyle, this.maxLines = 2, this.textScaleFactor = 1.0, }); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { final defaultStyle = DefaultTextStyle.of(context).style; final textStyle = this.textStyle ?? defaultStyle; final moreStyle = this.moreStyle ?? textStyle.copyWith(color: Colors.blue); // 先算原始文本的布局情况 final textPainter = TextPainter( text: TextSpan(text: text, style: textStyle), maxLines: maxLines, textScaleFactor: textScaleFactor, textDirection: TextDirection.ltr, )..layout(maxWidth: constraints.maxWidth); // 没溢出的话直接显示完整文本 if (!textPainter.didExceedMaxLines) { return Text(text, style: textStyle, maxLines: maxLines); } // 溢出的话,逐步截断文本,直到加省略号和more后刚好不超行数 const ellipsis = '...'; final ellipsisSpan = TextSpan(text: ellipsis, style: textStyle); final moreSpan = TextSpan(text: moreText, style: moreStyle); String truncatedText = text; while (true) { if (truncatedText.isEmpty) break; final testSpan = TextSpan( children: [ TextSpan(text: truncatedText, style: textStyle), ellipsisSpan, moreSpan, ], ); final testPainter = TextPainter( text: testSpan, maxLines: maxLines, textScaleFactor: textScaleFactor, textDirection: TextDirection.ltr, )..layout(maxWidth: constraints.maxWidth); if (!testPainter.didExceedMaxLines) { break; } truncatedText = truncatedText.substring(0, truncatedText.length - 1); } return RichText( text: TextSpan( children: [ TextSpan(text: truncatedText, style: textStyle), ellipsisSpan, moreSpan, ], ), maxLines: maxLines, overflow: TextOverflow.visible, ); }, ); } } // 用的时候直接这么写 class DemoPage extends StatelessWidget { const DemoPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('多行溢出测试')), body: Padding( padding: const EdgeInsets.all(16.0), child: OverflowTextWithMore( text: '这是一段用来测试的超长文本,就是为了验证多行溢出时,省略号后面能精准跟着more按钮,不会出现垂直错位的情况,完全符合设计要求。', moreText: 'more', maxLines: 2, moreStyle: const TextStyle(color: Colors.blue, fontSize: 14), ), ), ); } }
方案说明
- 先通过
LayoutBuilder拿到组件能使用的宽度,保证计算出来的结果准确; - 用
TextPainter判断原始文本会不会溢出,没溢出就直接显示完整内容; - 如果溢出了,就一点点截断原始文本,直到加上省略号和“more”后,整体刚好不超过设定的最大行数;
- 最后用
RichText把截断后的文本、省略号和“more”拼起来,完美实现效果。
为啥之前的方案不行?
- 单行的方案靠
Text组件的overflow属性就能搞定,但多行时默认的省略号是在最后一行末尾,直接拼“more”会被挤到下一行或者垂直对齐出错; - 直接用
RichText没做溢出计算,没法动态截断文本并控制总行数,自然达不到想要的效果。
内容的提问来源于stack exchange,提问作者chris
相关产品推荐
相关产品推荐

