Last active
October 8, 2022 15:32
-
-
Save BarryDaBee/3f367f5705428eb27e4a4d9842f13e88 to your computer and use it in GitHub Desktop.
Implementation of common "Read more" feature to truncate and expand lengthy text on demand
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/gestures.dart'; | |
import 'package:flutter/material.dart'; | |
class ReadMore extends StatefulWidget { | |
final String text; | |
final TextStyle? textStyle; | |
final String readMoreText; | |
final TextStyle? readMoreTextStyle; | |
final int maxLines; | |
final int steps; | |
// final bool shouldUseSteps; | |
const ReadMore({ | |
Key? key, | |
this.readMoreText = 'Read more', | |
this.readMoreTextStyle, | |
this.maxLines = 4, | |
required this.text, | |
this.textStyle, | |
this.steps = 4, | |
// required this.shouldUseSteps, | |
}) : super(key: key); | |
@override | |
State<ReadMore> createState() => _ReadMoreState(); | |
} | |
class _ReadMoreState extends State<ReadMore> { | |
late int _maxLines = widget.maxLines; | |
String get _readMoreText => ' ' + widget.readMoreText; | |
@override | |
Widget build(BuildContext context) { | |
return _buildMessage(); | |
} | |
TextSpan _bodyTextSpan() { | |
return TextSpan(text: widget.text, style: widget.textStyle); | |
} | |
TextSpan _readMoreTextSpan() { | |
return TextSpan( | |
text: _readMoreText, | |
style: widget.readMoreTextStyle, | |
recognizer: TapGestureRecognizer() | |
..onTap = () { | |
setState(() { | |
_maxLines += widget.steps; | |
}); | |
}, | |
); | |
} | |
RichText _buildMessage() { | |
const double maxWidth = 300; | |
const double minWidth = 0; | |
TextPainter textPainter = TextPainter( | |
text: _readMoreTextSpan(), | |
textDirection: TextDirection.ltr, | |
maxLines: _maxLines, | |
ellipsis: '', | |
); | |
textPainter.layout(minWidth: minWidth, maxWidth: maxWidth); | |
final linkSize = textPainter.size; | |
textPainter.text = _bodyTextSpan(); | |
textPainter.layout(minWidth: minWidth, maxWidth: maxWidth); | |
final textSize = textPainter.size; | |
int? endIndex; | |
final pos = textPainter.getPositionForOffset(Offset( | |
textSize.width - linkSize.width, | |
textSize.height, | |
)); | |
endIndex = textPainter.getOffsetBefore(pos.offset); | |
TextSpan textSpan; | |
if (textPainter.didExceedMaxLines) { | |
textSpan = TextSpan( | |
text: widget.text.substring(0, endIndex), | |
children: <TextSpan>[_readMoreTextSpan()], | |
); | |
} else { | |
textSpan = TextSpan( | |
text: widget.text, | |
); | |
} | |
return RichText( | |
softWrap: true, | |
text: textSpan, | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment