How to Get the Number of Text Lines In our Flutter project, we need to determine if the number of lines of text exceeds 3, then we will display a prompt message. How can we use the code to implement it?
How to Get the Number of Text Lines In our Flutter project, we need to determine if the number of lines of text exceeds 3, then we will display a prompt message. How can we use the code to implement it?
If you simply want to know how many intrinsic lines the text contains, you can do a simple
final numLines = '\n'.allMatches(yourText).length + 1;
However, I guess you're more interested in the number of lines that are actually being displayed visually.
Here, things get a little more complicated, because you need to know the available space (the BoxConstraints) in order to calculate how many lines the text needs.
To do that, you can use a LayoutBuilder to delay the widget building and a TextPainter to do the actual calculation:
return LayoutBuilder(builder: (context, constraints) {
final span = TextSpan(text: yourText, style: yourStyle);
final tp = TextPainter(text: span);
tp.layout(maxWidth: constraints.maxWidth);
final numLines = textPainter.computeLineMetrics().length;
if (numLines > 3) {
// TODO: display the prompt message
return ColoredBox(color: Colors.red);
} else {
return Text(yourText, style: yourStyle);
}
});
I extracted some of the code from the auto_size_text pub package, which might also be interesting to you:
It sizes its text so it fits in the given space.
Anyhow, be careful when displaying the prompt:
Your widget's build method may be called several times per second, resulting in multiple prompts being displayed simultaneously.
Note: The computeLineMetrics() function was added after the initial version of the answer. That's why a previous version of this answer used a TextPainter(text: span, maxLines: 3) and then checked if tp.didExceedMaxLines.
Update: this answer is here for historical purposes. See my updated answer here for a much easier solution.
If you have a TextPainter object and you have already called layout, then you can get the number of lines by selecting everything and calling getBoxesForSelection. Each box is the size of the line.
TextSelection selection = TextSelection(baseOffset: 0, extentOffset: text.length);
List<TextBox> boxes = textPainter.getBoxesForSelection(selection);
int numberOfLines = boxes.length;
Here is an example:
final text = 'My text line.\nThis line wraps to the next.\nAnother line.';
print(numberOfLines); // 4
Unfortunately, this fails if there is a mix of bidirectional text:
final text = 'My text line.\nThis كلمة makes more boxes.\nAnother line.';
print(numberOfLines); // 6
This could be overcome by only counting the boxes that along one edge. If you notice the data from above, there are only four boxes that have an edge at 0.0.
flutter: TextBox.fromLTRBD(0.0, 0.2, 171.8, 36.0, TextDirection.ltr)
flutter: TextBox.fromLTRBD(0.0, 36.5, 68.4, 72.3, TextDirection.ltr)
flutter: TextBox.fromLTRBD(68.4, 38.2, 111.5, 75.0, TextDirection.rtl)
flutter: TextBox.fromLTRBD(111.5, 36.5, 299.9, 72.3, TextDirection.ltr)
flutter: TextBox.fromLTRBD(0.0, 77.2, 92.2, 113.0, TextDirection.ltr)
flutter: TextBox.fromLTRBD(0.0, 113.2, 179.7, 149.0, TextDirection.ltr)
I wish there were a TextPainter.numberOfLines method, but I haven't found it.
It is now easy to find the number of lines in a paragraph:
List<ui.LineMetrics> lines = textPainter.computeLineMetrics();
int numberOfLines = lines.length;
Notes
computeLineMetrics must be called after layout.See also
I just got backed by this code , hence this is how I validate whether it crosses the maxlines or not
var text="Clita takimata dolor diam magna aliquyam et sed dolores sadipscing. Sed ut
diam rebum labore sadipscing sit amet, diam labore.";
final span=TextSpan(text:text);
final tp =TextPainter(text:span,maxLines: 3,textDirection: TextDirection.ltr);
tp.layout(maxWidth: MediaQuery.of(context).size.width); // equals the parent screen width
print(tp.didExceedMaxLines);
//false for maxlines 3
//true for maxlines 1
in my case I needed to get number of Lines to change height based of it , but instead I used Stack widget as a work around . Here is my Code :
Container(
height: AppTheme.fullHeight(context) *.08,
child: Stack(
children: [
Container(
height: AppTheme.fullHeight(context) *.08,
child: Text(
"${products[index].name!}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12,color: Utils.secondaryColor),),
),
//SizedBox(height: MediaQuery.of(context).size.height * .01,),
Positioned(
bottom: AppTheme.fullHeight(context) *.0,
left: 0,
child: Text(
products[index].price! + Constants.CURRENCY.tr,
style: TextStyle(fontSize: 16,
fontWeight: FontWeight.bold,color: Utils.secondaryColor),),
)
],
),
),
just place property maxLines: null, and TextInputAction.done, if you want restrict new lines to a particular limit count "\n" .