How can I prevent a multi-line Text widget from getting clipped when placed within a Row?

3,347

The most important thing to know is that child widgets within a Column or Row take up as much space as they need by default.

Child elements by themselves are not bounded by the main axis size (width/height) of the row/column and will overflow if they are bigger. (Hence, why you see the red overflow indicator on the right)

Your behavior is not due to the text widget, but due to the layout itself. You need to constrain the width of the text widget to the remaining width in your Row layout between the two icons.

By wrapping child elements in a Expanded you can explicitly describe how each child widget will size inside the row.

A Expanded will size itself based on the other Expandeds in the row/column and the remaining space.

Lets take a look at an example to understand how a Expanded would work within a Row or Column:

var row = new Container(
  width: 400.0,
  height: 100.0,
  child: new Row(
    children: [
      // Red Bar
      // This will take up 50dp always, since it is not wrapped by a Expanded
      new Container(
        width: 50.0,
        decoration: new BoxDecoration(
          backgroundColor: Colors.red[500],
        )
      ),
      // Green Bar
      // This will take up 1/3 of the remaining space (1/3 of 350dp)
      new Expanded(
        flex: 1,
        child: new Container(
          decoration: new BoxDecoration(
            backgroundColor: Colors.green[500],
          )
        ),
      ),
      // Blue Bar
      // This will take up 2/3 of the remaining space (2/3 of 350dp)
      new Expanded(
        flex: 2,
        child: new Container(
          decoration: new BoxDecoration(
            backgroundColor: Colors.blue[500],
          )
        ),
      )
    ]
  ),
);

Which renders this:

Code Output

Lets break this down:

  1. The red bar always will be 50dp long because it is not wrapped in a Expanded. It will have a width of 50dp even if it is larger than the parent container.

  2. Now we have 350dp (400-350) to divvy up between the green bar and the blue bar.

  3. What we do now is add up all the remaining flex values for each Expanded, which gives us: 1[green] + 2[blue] = 3

  4. Now each Expanded will be a proportion of the remaining space based on the flex value of the Expanded and the cumulative flex values of all Expandeds: Green = 1/3, Blue = 2/3.

  5. So the green bar will have a width of 1/3 * 350 = 116.67dp

  6. And the blue bar will have a width of 2/3 * 350 = 233.33dp

Back to your original problem: all you need to do is to wrap your text widget inside a Expanded. By default, Expandeds have a flex value of 1. Since you only one Expanded in the row (1/1 = 100%), this text will take up the remaining space in the row.

Solution:

var container = new Container (
  child: new Row (
    children: [
      new Icon (Icons.navigate_before),
      new Expanded(
        child: new Text ("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."),
      ),      
      new Icon (Icons.navigate_next),
    ],
  ),
  decoration: new BoxDecoration (
    backgroundColor: Colors.grey[300],
  ),
  width: 400.0,
);
Share:
3,347
bkobash
Author by

bkobash

Updated on December 01, 2022

Comments

  • bkobash
    bkobash over 1 year

    I have a Text widget in my Flutter app that contains a long text string. It's placed within a Container that has a fixed width. By default, the text string wraps to multiple lines.

    However, when I try to insert that Text widget into a Row widget, the text string suddenly switches to a single line, and gets clipped on the right side.

    What's an easy way to keep the Text widget's original multi-line behavior when it's within a Row?

    multi-line switches to single line

    Here's the code I've been using:

    var container = new Container (
      child: new Row (
        children: [
          new Icon (Icons.navigate_before),
          new Text ("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."),
          new Icon (Icons.navigate_next),
        ],
      ),
      decoration: new BoxDecoration (
        backgroundColor: Colors.grey[300],
      ),
      width: 400.0,
    );