Flutter 组件封装:文字折叠 NExpandText
一、需求来源
开发时遇到一个需求需要在文字超过一行时有展开和收起菜单,效果如下:
二、使用示例
Header.h4(title: "字符串不够一行时"),
Container(
color: Colors.yellowAccent,
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: NExpandText(
text: text.substring(0, 20),
textStyle: textStyle,
expandTitleStyle: TextStyle(color: Colors.green)
),
),
Header.h4(title: "字符串超过一行时(折叠)"),
Container(
color: Colors.yellow,
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: NExpandText(
text: text,
textStyle: textStyle,
expandTitleStyle: TextStyle(color: Colors.green)
),
),
Header.h4(title: "字符串超过一行时(展开)"),
Container(
color: Colors.yellow,
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: NExpandText(
text: text,
textStyle: textStyle,
expandTitleStyle: TextStyle(color: Colors.green)
),
),
三、组件源码
import 'package:flutter/material.dart';
import 'package:flutter_templet_project/extension/text_painter_ext.dart';
///如果文字超过一行,右边有展开收起按钮
class NExpandText extends StatefulWidget {
NExpandText({
Key? key,
required this.text,
required this.textStyle,
this.expandMaxLine = 10,
this.expandTitleStyle,
this.initiallyExpanded = false,
}) : super(key: key);
/// 字符串
String text;
/// 字符串样式
TextStyle textStyle;
/// 超过一行初始展开状态
bool initiallyExpanded;
/// 展开状态最大行
int expandMaxLine;
/// 展开按钮文字样式
TextStyle? expandTitleStyle;
@override
_NExpandTextState createState() => _NExpandTextState();
}
class _NExpandTextState extends State<NExpandText> {
@override
Widget build(BuildContext context) {
return buildText(
text: widget.text,
textStyle: widget.textStyle,
isExpand: widget.initiallyExpanded,
expandMaxLine: widget.expandMaxLine,
expandTitleStyle: widget.expandTitleStyle,
);
}
buildText({
required String text,
required TextStyle textStyle,
bool isExpand = false,
int expandMaxLine = 10,
TextStyle? expandTitleStyle,
}) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints){
final textPainter = TextPainterExt.getTextPainter(
text: text,
textStyle: textStyle,
maxLine: 100,
maxWidth: constraints.maxWidth,
);
final numberOfLines = textPainter.computeLineMetrics().length;
// debugPrint("numberOfLines:${numberOfLines}");
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
final btnTitle = isExpand ? "收起" : "展开";
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(19))
),
child: Container(
// color: Colors.green,
padding: EdgeInsets.symmetric(vertical: 8),
child: Text(text,
style: textStyle,
maxLines: isExpand ? expandMaxLine : 1,
),
),
),
),
if(numberOfLines > 1) TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
minimumSize: Size(50, 18),
),
onPressed: (){
isExpand = !isExpand;
setState((){});
},
child: Text(btnTitle, style: expandTitleStyle,),
),
],
);
}
);
}
);
}
}
总结
核心是通过 TextPainter 布局后获取行数代码:
final numberOfLines = textPainter.computeLineMetrics().length;
然后做尺寸判断进行处理,目前最优的方法。
转载自:https://juejin.cn/post/7239630585500221497