当前位置: 首页> 健康> 养生 > Flutter之自定义封装实现在文本结尾处拼接...展开/收起的ExpandableText

Flutter之自定义封装实现在文本结尾处拼接...展开/收起的ExpandableText

时间:2025/7/10 2:59:29来源:https://blog.csdn.net/guolipeng_network/article/details/140328845 浏览次数:0次

前言

最近在忙着写Flutter来适配跨端,完成Android、iOS、HarmonyOS三端通用一套代码,降低人力维护成本,项目中遇到了需要实现像之前Android原生一样的在一段文本超过最大行数时,在结尾处截断并拼接展开/收起。一开始不太熟悉,就先用Stack自己动态控制maxLines以及overflow,在右下角盖上去一个遮罩以及文本来实现的,后来发现有些屏幕手机会出现文字被盖住一部分漏出半个字的囧状,今天终于有时间优化一下实现方案了。

实现代码

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';class ExpandableText extends StatefulWidget {final String text;final int maxLines;final TextStyle textStyle;final String linkTextExpand;final String linkTextCollapse;final Color linkTextColor;const ExpandableText({super.key,required this.text,this.maxLines = 2,this.textStyle = const TextStyle(color: Colors.black),this.linkTextColor = Colors.blue,this.linkTextExpand = " 展开",this.linkTextCollapse = " 收起"});State<StatefulWidget> createState() => _ExpandableTextState();
}class _ExpandableTextState extends State<ExpandableText> {bool isExpanded = false;late TextSpan expandSpan;late TextSpan linkTextSpan;void initState() {super.initState();expandSpan = TextSpan(text: widget.linkTextExpand,style: TextStyle(color: widget.linkTextColor),recognizer: TapGestureRecognizer()..onTap = () {setState(() {isExpanded = !isExpanded;});},);linkTextSpan = TextSpan(text: '...',style: widget.textStyle,children: [expandSpan],);}/// 检查文本是否溢出bool checkOverflow(double width) {final textPainter = TextPainter(text: TextSpan(text: widget.text, style: widget.textStyle),textDirection: TextDirection.ltr,);textPainter.layout(maxWidth: width);return textPainter.height > widget.maxLines * textPainter.preferredLineHeight;}Widget build(BuildContext context) {return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {final maxWidth = constraints.maxWidth;final textSpan = TextSpan(text: widget.text,style: widget.textStyle,);final textPainter = TextPainter(text: textSpan,maxLines: isExpanded ? null : widget.maxLines,textDirection: TextDirection.ltr,);textPainter.layout(maxWidth: maxWidth);return Column(crossAxisAlignment: CrossAxisAlignment.start,children: [isExpanded ? _buildExpandedText() : _buildCollapsedText(textPainter, maxWidth),],);},);}/// 构建折叠状态下的文本Widget _buildCollapsedText(TextPainter textPainter, double maxWidth) {var truncatedText = widget.text;if (checkOverflow(maxWidth)) {// 文本的长度超过了最大行数,需要截取然后拼接展开部分的逻辑final linkPainter = TextPainter(text: linkTextSpan,textDirection: TextDirection.ltr,);linkPainter.layout(maxWidth: maxWidth);final position = textPainter.getPositionForOffset(Offset(maxWidth - linkPainter.width, textPainter.height));final endOffset = textPainter.getOffsetBefore(position.offset) ?? position.offset;truncatedText = widget.text.substring(0, endOffset);}return RichText(text: TextSpan(text: truncatedText,style: widget.textStyle,children: widget.text.length == truncatedText.length ? [] : [linkTextSpan],),maxLines: widget.maxLines,overflow: TextOverflow.ellipsis,);}/// 构建展开状态下的文本Widget _buildExpandedText() {final collapseSpan = TextSpan(text: widget.linkTextCollapse,style: TextStyle(color: widget.linkTextColor),recognizer: TapGestureRecognizer()..onTap = () {setState(() {isExpanded = !isExpanded;});},);return RichText(text: TextSpan(text: widget.text,style: widget.textStyle,children: [collapseSpan],),);}
}

功能概述

ExpandableText 是一个自定义的Flutter widget,用于展示长文本内容。当文本长度超过预设的最大行数时,文本会被折叠并显示一个“展开”链接,点击后可以完全展开文本,再次点击则折叠文本。

关键实现点

1. 状态管理:

使用 StatefulWidget 和 _ExpandableTextState 来管理文本的展开/折叠状态。
isExpanded 变量控制文本的显示状态。

2. 文本处理:

利用 TextPainter 和 RichText 组件来测量和渲染文本。
当文本超出最大行数时,通过计算和截取文本,确保文本在折叠状态下正确显示,并添加“展开”链接。

3. 交互逻辑:

通过 TapGestureRecognizer 添加点击事件监听,实现“展开”和“收起”功能。
setState 方法用于更新文本的显示状态。

4. 响应式布局:

使用 LayoutBuilder 获取可用宽度,以适应不同屏幕尺寸和布局环境。
checkOverflow 方法用于判断文本是否超出设定的最大行数。

5. 样式定制:

提供了多个可配置参数,如 maxLines, textStyle, linkTextExpand, linkTextCollapse, linkTextColor,允许用户自定义文本的外观和行为。

6. 使用方法

ExpandableText(text: "这是一段很长的文本,它将被折叠起来,只有在点击'展开'链接后才会完全显示。",maxLines: 2,textStyle: TextStyle(fontSize: 16, color: Colors.black),linkTextExpand: " 展开",linkTextCollapse: " 收起",linkTextColor: Colors.blue,
);

注意事项

确保在使用 ExpandableText 时,提供足够的上下文宽度,以便正确计算文本的折叠点。
自定义样式参数应根据实际需求进行调整,以达到最佳的视觉效果。

关键字:Flutter之自定义封装实现在文本结尾处拼接...展开/收起的ExpandableText

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: