Flutter中如何为TextSpan设置自动字号并实现等宽行间分割线
富文本自动适配字体大小实现
社区维护的auto_size_text包原生支持富文本场景,无需自定义复杂缩放逻辑:
- 使用
AutoSizeText.rich构造方法传入带多TextSpan的富文本结构,不要单独给Text外层包裹独立缩放组件 - 核心配置项说明:
minFontSize/maxFontSize:设置允许适配的字体大小范围,避免字体缩到过小或超出设计规范上限stepGranularity:设置字体调整的步长,一般设为1保证字体平滑缩放maxLines:指定最大行数,保证适配逻辑不会因为无限换行破坏原有排版结构- 核心示例代码:
AutoSizeText.rich( TextSpan( children: [ TextSpan(text: "常规内容", style: TextStyle(fontSize: 16, color: Colors.black)), TextSpan(text: "重点强调内容", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.red)), ], ), minFontSize: 12, maxFontSize: 18, stepGranularity: 1, maxLines: 3, overflow: TextOverflow.ellipsis, )
踩坑提醒:不要通过文本字数估算宽度做字体适配,中英文混排、字间距调整、字重变化都会造成实际渲染宽度和估算值存在明显误差。
行间插入与文本等长分割线实现
常规的Row组合方案(文本加Expanded分割线)会让分割线撑满整个容器宽度,无法匹配实际文本行长度,正确实现需要基于行级渲染度量做绘制:
- 核心思路:自定义继承
RenderParagraph,直接复用TextPainter计算出的精确行度量数据,在两行的间隙位置绘制和当前行等宽的分割线,无宽度估算误差 - 关键实现逻辑:
- 重写
RenderParagraph的paint方法 - 通过
textPainter.computeLineMetrics()获取每一行的精确坐标、实际渲染宽度、上下边距数据 - 逐行遍历计算两行之间的间隙中点位置,从当前行的左边缘开始,绘制长度等于当前行实际宽度的水平分割线
- 重写
- 核心绘制代码片段:
@override void paint(PaintingContext context, Offset offset) { super.paint(context, offset); final canvas = context.canvas; final splitLinePaint = Paint() ..color = Colors.grey[300]! ..strokeWidth = 1; // 获取所有行的精确渲染度量 final lineMetrics = textPainter.computeLineMetrics(); for (int i = 0; i < lineMetrics.length - 1; i++) { final currentLine = lineMetrics[i]; final nextLine = lineMetrics[i+1]; // 计算两行间隙的垂直中点 final splitY = offset.dy + currentLine.baseline + currentLine.descent + (nextLine.baseline - currentLine.baseline - currentLine.descent)/2; // 绘制和当前行等宽的分割线 canvas.drawLine( offset.translate(currentLine.left, splitY), offset.translate(currentLine.left + currentLine.width, splitY), splitLinePaint, ); } }
效果说明:该方案拿到的行宽度是文本实际渲染的精确值,无论文本是左对齐、居中对齐还是带缩进,分割线都能和相邻行的文本边缘完全对齐,不会出现凸出或短截的问题。
内容的提问来源于stack exchange,提问作者MikeL
相关产品推荐
相关产品推荐

