Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if Flutter Text widget was overflowed

Tags:

flutter

dart

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?

What I've tried

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.

like image 560
Lian Avatar asked Jun 30 '18 12:06

Lian


People also ask

What is TextOverflow in Flutter?

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.

How do I show rich text in Flutter?

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.


2 Answers

I found a way to do it. Full code below, but in short:

  1. Use a LayoutBuilder to determine how much space we have.
  2. Use a TextPainter to simulate the render of the text within the space.

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,
          ),
        ],
      ),
    );
  }
}
like image 141
Lian Avatar answered Oct 04 '22 04:10

Lian


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;
}
like image 35
Valentina Konyukhova Avatar answered Oct 04 '22 04:10

Valentina Konyukhova