likes
comments
collection
share

Flutter 组件封装:文字折叠 NExpandText

作者站长头像
站长
· 阅读数 19

一、需求来源

开发时遇到一个需求需要在文字超过一行时有展开和收起菜单,效果如下:

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;

然后做尺寸判断进行处理,目前最优的方法。

github

转载自:https://juejin.cn/post/7239630585500221497
评论
请登录