I have a Text widget which can be truncated if it exceeds a certain size:
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 50.0),
child: Text(
widget.review,
overflow: TextOverflow.ellipsis,
)
);
Or max number of lines:
RichText(
maxLines: 2,
overflow: TextOverflow.ellipsis,
text: TextSpan(
style: TextStyle(color: Colors.black),
text: widget.review,
));
My goal is to have the text expandable only if an overflow occurred. Is there a proper way of checking if the text overflowed?
I have found that in RichText, there is a RenderParagraph renderObject
, which has a private property TextPainter _textPainter
which has a bool didExceedMaxLines
.
In short, I just need to access richText.renderObject._textPainter.didExceedMaxLines
but as you can see, it is made private with the underscore.
In Flutter, the overflow property of the Text, RichText, and DefaultTextStyle widgets specifies how overflowed content that is not displayed should be signaled to the user. It can be clipped, display an ellipsis (three dots), fade, or overflowing outside its parent widget. Overview. Examples. TextOverflow.clip.
The RichText widget is used to display text that uses various different styles. The displayed text is described using a tree of TextSpan objects, each of which has its own associated style that is used for that subtree.
I found a way to do it. Full code below, but in short:
Here's the full demo app:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Text Overflow Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(title: Text("DEMO")),
body: TextOverflowDemo(),
),
);
}
}
class TextOverflowDemo extends StatefulWidget {
@override
_EditorState createState() => _EditorState();
}
class _EditorState extends State<TextOverflowDemo> {
var controller = TextEditingController();
@override
void initState() {
controller.addListener(() {
setState(() {
mytext = controller.text;
});
});
controller.text = "This is a long overflowing text!!!";
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
String mytext = "";
@override
Widget build(BuildContext context) {
int maxLines = 1;
double fontSize = 30.0;
return Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: <Widget>[
LayoutBuilder(builder: (context, size) {
// Build the textspan
var span = TextSpan(
text: mytext,
style: TextStyle(fontSize: fontSize),
);
// Use a textpainter to determine if it will exceed max lines
var tp = TextPainter(
maxLines: maxLines,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
text: span,
);
// trigger it to layout
tp.layout(maxWidth: size.maxWidth);
// whether the text overflowed or not
var exceeded = tp.didExceedMaxLines;
return Column(children: <Widget>[
Text.rich(
span,
overflow: TextOverflow.ellipsis,
maxLines: maxLines,
),
Text(exceeded ? "Overflowed!" : "Not overflowed yet.")
]);
}),
TextField(
controller: controller,
),
],
),
);
}
}
There is a shorter way to get an answer if text is overflowed or not. You just need to define textStyle and get the answer from this method
bool hasTextOverflow(
String text,
TextStyle style,
{double minWidth = 0,
double maxWidth = double.infinity,
int maxLines = 2
}) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: maxLines,
textDirection: TextDirection.ltr,
)..layout(minWidth: minWidth, maxWidth: maxWidth);
return textPainter.didExceedMaxLines;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With