Reputation: 8212
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:
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
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):
flex
value ("normal widget"):
It gives to the child no max constraint for the layout and gets its size.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
.
Expanded
would be laid out with a maxWidth = 100
. Since it is an Expanded
its width
will be 100
.Flexible
widget is also laid out with a maxWidth = 100
. But its size could be 50
(and not 100
).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
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