preface
Having nothing to do, I continue to learn. This time, I have realized a function of expanding and folding multi-line text. The relevant code has been uploaded to Github, and the component source code.
- use
LayoutBuilder
To implement control lazy loading - use
TextPainter
Determines whether the text content exceeds the specified number of lines- More than
- by
TextPainter
The built-in method calculates how many lines of text to intercept before - Concatenate captured text with expand/display (concatenate with TextSpan)
- by
- If not, the original text is displayed
- More than
Implementation steps
Use LayoutBuilder to realize control lazy loading
return LayoutBuilder(builder: (context, constraints) {
}
Copy the code
Use TextPainter to determine if the text content exceeds the specified number of lines
TextPainter _textPainter = TextPainter( maxLines: widget.maxLines, textScaleFactor: MediaQuery.textScaleFactorOf(context), locale: Localizations.localeOf(context), textAlign: TextAlign.start, text: TextSpan( text: widget.text, style: widget.textStyle, ), textDirection: Directionality.of(context)) .. layout( minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);Copy the code
TextPainter’s built-in method calculates how many lines of text to intercept
final textSize = _textPainter.size; final position = _textPainter.getPositionForOffset(Offset( textSize.width - _textPainter.width, textSize.height, )); // Default endOffset = position. offset-1; But this can sometimes lead to two word wrap, so it will be a reduction of the 1 final endOffset = _textPainter. GetOffsetBefore (position. The offset - 1);Copy the code
Concatenate captured text with expand/display (concatenate with TextSpan)
Return RichText(overflow: textoverflow. clip, text: TextSpan(// cut 0-endoffset string, and expand/collapse text:! _isExpand ? widget.text : widget.text.substring(0, endOffset), style: TextStyle(color: Colors.black), children: [ TextSpan( text: _isExpand ? widget.shrinkText : widget.expandText, style: TextStyle(color: Colors.lightBlueAccent), recognizer: TapGestureRecognizer()..onTap = () {setState(() {_isExpand =!_isExpand;});})]);Copy the code
The complete component code is shown below
import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; class CommonRichText extends StatefulWidget { final String text; final int maxLines; final int minLines; final TextStyle? textStyle; final String shrinkText; final String expandText; final Function? onShrink; final Function? onExpand; CommonRichText({this.text = ", this.maxlines = 4, this.minlines = 1, this.textstyle, this.shrinkText = 'expand ', This.expandtext = 'shrink ', this.onexpand, this.onexpand}); _RichTextState createState() => _RichTextState(); } class _RichTextState extends State<CommonRichText> { bool _isExpand = true; @override void initState() { // TODO: implement initState super.initState(); } @override void didUpdateWidget(covariant CommonRichText oldWidget) { // TODO: implement didUpdateWidget super.didUpdateWidget(oldWidget); } @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context, constraints) { TextPainter _textPainter = TextPainter( maxLines: widget.maxLines, textScaleFactor: MediaQuery.textScaleFactorOf(context), locale: Localizations.localeOf(context), textAlign: TextAlign.start, text: TextSpan( text: widget.text, style: widget.textStyle, ), textDirection: Directionality.of(context)) .. layout( minWidth: constraints.minWidth, maxWidth: constraints.maxWidth); / / determine whether has exceeded maximum number of lines if (_textPainter. DidExceedMaxLines) {final textSize = _textPainter. Size; final position = _textPainter.getPositionForOffset(Offset( textSize.width - _textPainter.width, textSize.height, )); // Default endOffset = position. offset-1; But this can sometimes lead to two word wrap, so it will be a reduction of the 1 final endOffset = _textPainter. GetOffsetBefore (position. The offset - 1); Return RichText(overflow: textoverflow. clip, text: TextSpan(// cut 0-endoffset string, and expand/collapse text:! _isExpand ? widget.text : widget.text.substring(0, endOffset), style: TextStyle(color: Colors.black), children: [ TextSpan( text: _isExpand ? widget.shrinkText : widget.expandText, style: TextStyle(color: Colors.lightBlueAccent), recognizer: TapGestureRecognizer()..onTap = () {setState(() {_isExpand =!_isExpand;});})]); } else { return Text.rich(TextSpan(text: widget.text)); }}); }}Copy the code
The interface display is as follows