介绍
对长文本进行省略展示,支持展开/收起,对省略位置可以自定义
c2b2bc33-ed77-4ad3-b50d-51d003bf5c52.gif
代码演示
基础用法
HcTextEllipsis(
content:"生态文明建设是关系中华民族永续发展的根本大计。总书记指出,要把建设美丽中国摆在强国建设、民族复兴的突出位置,以高品质生态环境支撑高质量发展,加快推进人与自然和谐共生的现代化。各地坚持以习近平生态文明思想为指引,牢固树立和践行绿水青山就是金山银山的理念,以更高站位、更宽视野、更大力度,全面推进美丽中国建设。"
),
最大显示行数
HcTextEllipsis(
maxLines: 2,
content:"生态文明建设是关系中华民族永续发展的根本大计。总书记指出,要把建设美丽中国摆在强国建设、民族复兴的突出位置,以高品质生态环境支撑高质量发展,加快推进人与自然和谐共生的现代化。各地坚持以习近平生态文明思想为指引,牢固树立和践行绿水青山就是金山银山的理念,以更高站位、更宽视野、更大力度,全面推进美丽中国建设。"
),
省略符位置
HcTextEllipsis(
maxLines: 2,
position: HcTextEllipsisPosition.center,
content:"生态文明建设是关系中华民族永续发展的根本大计。总书记指出,要把建设美丽中国摆在强国建设、民族复兴的突出位置,以高品质生态环境支撑高质量发展,加快推进人与自然和谐共生的现代化。各地坚持以习近平生态文明思想为指引,牢固树立和践行绿水青山就是金山银山的理念,以更高站位、更宽视野、更大力度,全面推进美丽中国建设。"
),
替换省略符
HcTextEllipsis(
maxLines: 2,
ellipsisDots: "~~~",
position: HcTextEllipsisPosition.center,
content:"生态文明建设是关系中华民族永续发展的根本大计。总书记指出,要把建设美丽中国摆在强国建设、民族复兴的突出位置,以高品质生态环境支撑高质量发展,加快推进人与自然和谐共生的现代化。各地坚持以习近平生态文明思想为指引,牢固树立和践行绿水青山就是金山银山的理念,以更高站位、更宽视野、更大力度,全面推进美丽中国建设。"
),
展开按钮单独显示
HcTextEllipsis(
maxLines: 2,
ellipsisDots: "~~~",
separateShow: false,
position: HcTextEllipsisPosition.center,
content:"生态文明建设是关系中华民族永续发展的根本大计。总书记指出,要把建设美丽中国摆在强国建设、民族复兴的突出位置,以高品质生态环境支撑高质量发展,加快推进人与自然和谐共生的现代化。各地坚持以习近平生态文明思想为指引,牢固树立和践行绿水青山就是金山银山的理念,以更高站位、更宽视野、更大力度,全面推进美丽中国建设。"
),
点击按钮的回调
HcTextEllipsis(
maxLines: 5,
ellipsisDots: "...",
separateShow: false,
showEllipsisBtn: true,
position: HcTextEllipsisPosition.center,
callback: (bool state) {
//设定回调后手动控制是否展开 返回true为展开 false为不展开
return Future.value(!state);
},
content:
"生态文明建设是关系中华民族永续发展的根本大计。总书记指出,要把建设美丽中国摆在强国建设、民族复兴的突出位置,以高品质生态环境支撑高质量发展,加快推进人与自然和谐共生的现代化。各地坚持以习近平生态文明思想为指引,牢固树立和践行绿水青山就是金山银山的理念,以更高站位、更宽视野、更大力度,全面推进美丽中国建设。"),
API
props
参数 | 说明 | 类型 | 默认值 | 是否必填 |
---|---|---|---|---|
maxLines | 需要展示的行数 | int | 1 | true |
content | 文字内容 | String | - | true |
expandText | 展开按钮的文字内容 | String | 展开 | true |
collapseText | 收起按钮的文字内容 | String | 收起 | true |
ellipsisDots | 省略符 | String | ... | true |
position | 分隔符的位置 | HcTextEllipsisPosition | end | true |
isExpand | 默认是否展开 | bool | false | true |
showEllipsisBtn | 是否展示更多的按钮 | bool | false | true |
separateShow | 按钮是否单独展示 | bool | false | true |
contentStyle | 文字的字体样式 | TextStyle? | - | false |
btnTextStyle | 按钮的文字样式 | TextStyle? | - | false |
callback | 点击的时候回调 | HcTextEllipsisCallback | - | false |
HcTextEllipsisPosition
展示省略符号位置
参数名 | 说明 |
---|---|
start | 开头 |
center | 中部 |
end | 结尾 |
Function
方法名 | 说明 | 参数 | 返回类型 |
---|---|---|---|
HcTextEllipsisCallback | 点击按钮后的回调 | Function(bool) | Future<bool?> |
项目源码
enum HcTextEllipsisPosition { start, center, end }
typedef HcTextEllipsisCallback = Future<bool?> Function(bool);
class HcTextEllipsis extends StatefulWidget {
//需要展示的行数
final int maxLines;
//文字内容
final String content;
//展开的文字
final String expandText;
//折叠的文字
final String collapseText;
///分隔符
final String ellipsisDots;
/// 文本的样式
final TextStyle contentStyle;
//按钮的 文字样式
final TextStyle btnTextStyle;
//点击按钮的回调
final HcTextEllipsisCallback? callback;
//分割符的位置
final HcTextEllipsisPosition position;
//是否展开
final bool isExpand;
//是否单独显示
final bool separateShow;
//是否展示拓展按钮
final bool showEllipsisBtn;
const HcTextEllipsis(
{Key? key,
this.isExpand = false,
this.maxLines = 1,
required this.content,
this.expandText = "展开",
this.collapseText = "收起",
this.ellipsisDots = "...",
this.position = HcTextEllipsisPosition.end,
this.contentStyle = const TextStyle(color: Colors.black, fontSize: 16),
this.callback,
this.btnTextStyle = const TextStyle(
color: Colors.blue, fontSize: 14, fontWeight: FontWeight.w500),
this.separateShow = false,
this.showEllipsisBtn = true})
: super(key: key);
@override
State<HcTextEllipsis> createState() => _HcTextEllipsisState();
}
class _HcTextEllipsisState extends State<HcTextEllipsis> {
//是否展开
bool _isExpand = false;
//组件的大小
Size _viewSize = const Size(0, 0);
//按钮组件的宽度
double btnWidth = 0.0;
//省略符号的宽度
double dotWidth = 0.0;
//文字高度
double fontHeight = 0.0;
//ellipsisLineWidth;
double ellipsisLineWidth = 0.0;
@override
void initState() {
super.initState();
_isExpand = widget.isExpand;
}
@override
void didUpdateWidget(covariant HcTextEllipsis oldWidget) {
super.didUpdateWidget(oldWidget);
_isExpand = widget.isExpand;
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, size) {
//按钮的宽度
btnWidth =
HcStringUtil.boundingTextSize(widget.expandText, widget.btnTextStyle)
.width;
//文字的宽度与高度
Size fontSize = HcStringUtil.boundingTextSize(
widget.ellipsisDots, widget.contentStyle);
dotWidth = fontSize.width;
fontHeight = fontSize.height;
//组件最大长度
_viewSize = Size(size.maxWidth, size.maxHeight);
//获取painter信息
TextPainter painter = HcStringUtil.getTextInfo(
widget.content, widget.contentStyle,
maxLines: widget.maxLines, width: _viewSize.width);
// 如果不满一行直接显示
if (!painter.didExceedMaxLines) {
return Text(widget.content, style: widget.contentStyle);
}
String result = "";
String content = widget.content;
switch (widget.position) {
case HcTextEllipsisPosition.start:
result = _buildEllipsisStartText(content, widget.maxLines);
break;
case HcTextEllipsisPosition.center:
if (widget.maxLines == 1) {
ellipsisLineWidth = _viewSize.width -
(!widget.separateShow && widget.showEllipsisBtn
? btnWidth
: 0) -
dotWidth;
int start = HcStringUtil.getTextInfo(content, widget.contentStyle,
width: (ellipsisLineWidth ~/ 2).toDouble())
.getPositionForOffset(
Offset((ellipsisLineWidth ~/ 2).toDouble(), 0))
.offset;
result = content.substring(0, start);
result += widget.ellipsisDots;
content = HcStringUtil.reverseString(content);
int end = HcStringUtil.getTextInfo(content, widget.contentStyle,
width:
ellipsisLineWidth - (ellipsisLineWidth ~/ 2).toDouble())
.getPositionForOffset(Offset(
ellipsisLineWidth - (ellipsisLineWidth ~/ 2).toDouble(), 0))
.offset;
result += HcStringUtil.reverseString(content.substring(0, end));
} else {
double halfLine = (widget.maxLines ~/ 2).toDouble();
result += _buildEllipsisEndText(content, widget.maxLines - halfLine,
showEllipsis: false);
result += _buildEllipsisStartText(content, halfLine);
}
break;
case HcTextEllipsisPosition.end:
result = _buildEllipsisEndText(content, widget.maxLines);
break;
}
return RichText(
text: TextSpan(
text: _isExpand ? widget.content : result,
style: widget.contentStyle,
children: [if (widget.showEllipsisBtn) _ellipsisBtn()]),
);
});
}
InlineSpan _ellipsisBtn() {
return TextSpan(
text: _isExpand ? widget.collapseText : widget.expandText,
style: widget.btnTextStyle,
recognizer: TapGestureRecognizer()
..onTap = () async {
bool isExpand = !_isExpand;
if (widget.callback != null) {
try {
isExpand = await widget.callback!.call(_isExpand) ?? isExpand;
} finally {}
}
setState(() {
_isExpand = isExpand;
});
});
}
String _buildEllipsisStartText(content, maxLines) {
String result = "";
// 反转文字截取最后
content = HcStringUtil.reverseString(content);
// 获取文字展示宽度
ellipsisLineWidth = _viewSize.width -
(!widget.separateShow && widget.showEllipsisBtn ? btnWidth : 0) -
(widget.maxLines == 1 ? dotWidth : 0);
// 获取阶段位置
int lastLineIndex = HcStringUtil.getTextInfo(content, widget.contentStyle,
width: _viewSize.width)
.getPositionForOffset(Offset(ellipsisLineWidth, 0))
.offset;
// 判断阶段位置展示的文字是否超过最大限度
double resultWidth = HcStringUtil.boundingTextSize(
content.substring(0, lastLineIndex), widget.contentStyle)
.width;
// 修正最大截取距离
lastLineIndex =
resultWidth > ellipsisLineWidth ? lastLineIndex - 1 : lastLineIndex;
String temp = content.substring(0, lastLineIndex);
if (maxLines > 1) {
content = content.substring(lastLineIndex);
if (maxLines > 2) {
int centerIndex = HcStringUtil.getTextInfo(content, widget.contentStyle,
width: _viewSize.width)
.getPositionForOffset(
Offset(_viewSize.width, fontHeight * (maxLines - 3)))
.offset;
temp += content.substring(0, centerIndex);
content = content.substring(centerIndex);
}
int firstIndex = HcStringUtil.getTextInfo(content, widget.contentStyle,
width: _viewSize.width - dotWidth)
.getPositionForOffset(Offset(_viewSize.width - dotWidth, 0))
.offset;
temp += content.substring(0, firstIndex);
}
result = widget.ellipsisDots;
result += HcStringUtil.reverseString(temp);
return result;
}
String _buildEllipsisEndText(content, maxLines, {bool showEllipsis = true}) {
String result = "";
if (maxLines > 1) {
int position = HcStringUtil.getTextInfo(content, widget.contentStyle,
width: _viewSize.width)
.getPositionForOffset(
Offset(_viewSize.width, fontHeight * (maxLines - 2)))
.offset;
result = content.substring(0, position);
content = content.substring(position);
}
ellipsisLineWidth = _viewSize.width -
(showEllipsis && (!widget.separateShow && widget.showEllipsisBtn)
? btnWidth
: 0) -
dotWidth;
int position = HcStringUtil.getTextInfo(content, widget.contentStyle,
width: ellipsisLineWidth)
.getPositionForOffset(Offset(ellipsisLineWidth, 0))
.offset;
result += content.substring(0, position);
if (showEllipsis) {
result += widget.ellipsisDots;
}
return result;
}
}
static Size boundingTextSize(String text, TextStyle style,
{int maxLines = 2 ^ 31,
double maxWidth = double.infinity,
textDirection = TextDirection.ltr}) {
if (text.isEmpty) {
return Size.zero;
}
final TextPainter textPainter = TextPainter(
textDirection: textDirection,
text: TextSpan(text: text, style: style),
maxLines: maxLines)
..layout(maxWidth: maxWidth);
return textPainter.size;
}
/// 获取文字信息
static TextPainter getTextInfo(String text, TextStyle style,
{int maxLines = 2 ^ 23,
double width = double.infinity,
String? ellipsis,
textDirection = TextDirection.ltr}) {
TextSpan span = TextSpan(text: text, style: style);
return TextPainter(
text: span,
maxLines: maxLines,
ellipsis: ellipsis,
textDirection: textDirection,
)..layout(maxWidth: width);
}
///翻转文字
static String reverseString(String str) {
return str.split("").reversed.join();
}
网友评论