首页 > 解决方案 > 在 Flutter 中扩展 RichText

问题描述

MessageWidget 返回一个以 RichText Widget 作为子级的 Container 。如果 RichText 的内容超过某个预定义的限制(例如 100 个字符),我想添加尾随文本“阅读更多”,因此当点击“阅读更多”时它会扩展。我遇到了这篇关于将 CustomPainter 与 TextSpan 结合使用的中型文章。我需要 RichText 类似的东西。

class Message extends StatelessWidget {
  final Widget _content;


  Message()
      : this._content = Content(),
        super(key: key);


  @override
  Widget build(BuildContext context) {
        ...
        return new Container(
            child: _content,
        );

  }



class Content extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    List<TextSpan> parsedText = createTextSpan(...);
    return RichText(
      text: TextSpan(children: parsedText),
    );
  }

标签: flutter

解决方案


工作示例:

class ExpandableText extends StatefulWidget {
  final String text;
  final int trimLines;
  final TextStyle style;

  const ExpandableText(
    this.text, {
    Key key,
    this.trimLines = 2,
    this.style,
  })  : assert(text != null),
        super(key: key);

  @override
  ExpandableTextState createState() => ExpandableTextState();
}

class ExpandableTextState extends State<ExpandableText> {
  bool _readMore = true;
  void _onTapLink() {
    setState(() => _readMore = !_readMore);
  }

  @override
  Widget build(BuildContext context) {
    TextSpan link = TextSpan(
        text: _readMore
            ? '... Read more'
            : ' Read less',
        style: TextStyle(
          color: Colors.blue,
        ),
        recognizer: TapGestureRecognizer()..onTap = _onTapLink);
    Widget result = LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        assert(constraints.hasBoundedWidth);
        final double maxWidth = constraints.maxWidth;
        // Create a TextSpan with data
        final text = TextSpan(
          text: widget.text,
          style: widget.style,
        );
        // Layout and measure link
        TextPainter textPainter = TextPainter(
          text: link,
          textDirection: TextDirection
              .rtl, //better to pass this from master widget if ltr and rtl both supported
          maxLines: widget.trimLines,
          ellipsis: '...',
        );
        textPainter.layout(minWidth: constraints.minWidth, maxWidth: maxWidth);
        final linkSize = textPainter.size;
        // Layout and measure text
        textPainter.text = text;
        textPainter.layout(minWidth: constraints.minWidth, maxWidth: maxWidth);
        final textSize = textPainter.size;
        // Get the endIndex of data
        int endIndex;
        final pos = textPainter.getPositionForOffset(Offset(
          textSize.width - linkSize.width,
          textSize.height,
        ));
        endIndex = textPainter.getOffsetBefore(pos.offset);
        var textSpan;
        if (textPainter.didExceedMaxLines) {
          textSpan = TextSpan(
            text: _readMore ? widget.text.substring(0, endIndex) : widget.text,
            style: widget.style,
            children: <TextSpan>[link],
          );
        } else {
          textSpan = TextSpan(
            text: widget.text,
            style: widget.style,
          );
        }
        return RichText(
          softWrap: true,
          overflow: TextOverflow.clip,
          text: textSpan,
        );
      },
    );
    return result;
  }
}

推荐阅读