Valentin Vignal
Valentin Vignal

Reputation: 8212

How to make a widget maximum size be equal to the flex value in a row

I have this small code:

Container(
  color: Colors.blue,
  child: Row(
    children: [
      Expanded(
        child: Container(
          color: Colors.red,
          child: const Text('Red text that can be long long long long long'),
        ),
      ),
      Flexible(
        child: Container(
          color: Colors.green,
          child: const Text('Small text'),
        ),
      ),
    ],
  ),
),

which renders into this:

enter image description here

Notice how the long text is wrapped even though there is still space around the small text.

I would like the small text to only take the size it needs to let the long text take the rest. And if the small text becomes bigger, its maximum size would be the size of the Flexible widget in the row (half of the Row in my example since both Expanded and Flexible have flex: 1).

If the small text is small enough, it should look like:

| Red text that can be long long long long | Small text |
| long                                     |            |

And if the "small" text is long too:

| Red text that can be long | Small text that is also  |
| long long long long       | very long                |

Is there a way to do that?

Upvotes: 1

Views: 1655

Answers (2)

Valentin Vignal
Valentin Vignal

Reputation: 8212

In the end, I used Yeasin Sheikh's answer so I'm validating it.

But I'm writing this comment to add more precisions on what I have found during my investigations.


At first, I wanted a simple widget like Flexible or Expanded (let's say LooseFlexible) to wrap my widget with:

Container(
  color: Colors.blue,
  child: Row(
    children: [
      Expanded(
        child: Container(
          color: Colors.red,
          child: const Text('Red text that can be long long long long long'),
        ),
      ),
      LooseFlexible(
        flex: 1
        child: Container(
          color: Colors.green,
          child: const Text('Small text'),
        ),
      ),
    ],
  ),
),

but it seems it would go against the way Flutter works.

I took a look a the flutter class RenderFlex, which is the render object the Flex class (a class that Row and Column are extending) returns in the method createRenderObject. It has a method _computeSizes, and inside it goes through the children (one by one):

  • if it does not have a flex value ("normal widget"): It gives to the child no max constraint for the layout and gets its size.
  • if it has a flex value (from Flexible or Expanded): it accumulates in a totalFlex value the some of all the flex (and does not render the child).

Then it goes through all the widgets that have a flex value and gives them as a max constraint (flex / totalFlex) * (maxConstraintOfParent - totalSizeOfNonFlexChildren) and layout them with it.

So each child is layout only once.


If my widget LooseFlexible were to exist, and if we had this code:

Row(
  children: [
    Expanded(flex: 1),
    LooseFlexible(flex: 1),
    Expanded(flex: 1),
  ],
),

Let's say the row has a maxWidth of 300. There is no non-flex children and totalFlex = 3.

  1. The 1st Expanded would be laid out with a maxWidth = 100. Since it is an Expanded its width will be 100.
  2. The Flexible widget is also laid out with a maxWidth = 100. But its size could be 50 (and not 100).
  3. Now comes the turn of the last Expanded, if we want it to take the entire remaining space, its size would be 150 which is not the same as the 1st Expanded with the same flex = 1 value. So the first child would need to be re-laid out, which is not following the flutter way of rendering children only once.

Upvotes: 1

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63604

You can use ConstrainedBox:constraints: BoxConstraints.loose( Size.fromWidth(maxWidth / 2) for green.

body:LayoutBuilder( 
  builder: (context, constraints) => Row(
    children: [
      Expanded(
        child: Container(
          color: Colors.red,
          child: const Text(
              'Red text that can be long long long lbe long long long lbe long long long long long'),
        ),
      ),
      ConstrainedBox(
        constraints: BoxConstraints.loose(
            Size.fromWidth(constraints.maxWidth / 2)),
        child: Container(
          color: Colors.green,
          child: const Text('Smalled g long th xt'),
        ),
      ),
    ],
  ),
),

Upvotes: 4

Related Questions