Fix minimum width to a Widget which needs to expand in Flutter - flutter

I need to fix a minimum width to my Column Widgets. Inside each of them, I have Text Widgets which can be very short or very long. I need to fix a minimum width to them in order to have an acceptable size of Column even if the text is short. The other Column need obviously to adapt himself.
Row(children: [
Column(
children: [
Container(
constraints: BoxConstraints(minWidth: 80), // do not work
child: Text("short text"),
),
],
),
Column(
children: [
Container(
constraints: BoxConstraints(minWidth: 110), // do not work
child: RichText(
text: TextSpan(
text:"very very longggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg text")),
),
],
),
],
)

There's probably a dozen ways to do what you want. And likely none of them straightforward or easy to understand. (The subject of constraints & sizes is quite complicated. See this constraints page for more examples & explanations.)
Here's one potential solution.
This will set a minimum width for the blue column (based on stepWidth), but will expand/grow if the text (child) inside wants to.
The yellow column will resize to accommodate the blue column.
class ExpandedRowPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Expanded Row Page'),
),
body: SafeArea(
child: Center(
child: Row(
children: [
IntrinsicWidth(
stepWidth: 100,
// BLUE Column
child: Container(
color: Colors.lightBlueAccent,
child: Column(
children: [
//Text('Short'),
Text('shrt')
],
)
),
),
// YELLOW Column
Flexible(
child: Container(
alignment: Alignment.center,
color: Colors.yellow,
child: Column(
children: [
Text('Very lonnnnnnnnnnnnnnnnnnnnnnnnnnnng texttttttttttttt'),
],
)
),
)
],
)
),
),
);
}
}
You could do the above without a Flexible yellow column, but a very long text child would cause an Overflow warning without a Flexible or Expanded wrapping widget.
A Row widget by itself has an infinite width constraint. So if a child wants to be bigger than screen width, it can, and will cause an overflow. (Try removing Flexible above and rebuild to see.)
Flexible and Expanded, used only inside Row & Column (or Flex, their superclass), checks screen width and other widgets inside a Row, and provides its children with a defined constraint size instead of infinite. Children (inside Flexible/Expanded) can now look up to parent for a constraint and size themselves accordingly.
A Text widget for example, will wrap its text when it's too wide for constraints given by Flexible/Expanded.

use FittedBox();
suppose Example:
Row(
children: [
Column(
children: [
Container(
constraints: BoxConstraints(minWidth: 80), // do not work
child: Text("short text"),
),
],
),
Column(
children: [
Container(
constraints: BoxConstraints(minWidth: 110), // do not work
child:
FittedBox(
child: RichText(
text: TextSpan(
text:
"very very longggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg text")),
),
),
],
),
],
);

Related

Button within Table within Gridview within Sizedbox or Flex is not clickable dependent on other table rows - Flutter

I am rendering a standard Table inside a GridView, inside a Flex inside a Row. The 2nd row of the table includes a Button.
When the contents of the first row of the table are above a certain size the clickable region of the button begins to cut off, missing entirely over a certain size.
Note: this is using Flutter Web, I have not tested on Mobile/Desktop.
I have created a minimal reproducible example in an attempt to isolate all logic.
Widget _render() {
return Row(mainAxisSize: MainAxisSize.max, children: [
SizedBox(
width: 900,
height: 900,
child: GridView.count(
crossAxisCount: 2,
children: <Widget>[
Table(border: TableBorder.all(), children: <TableRow>[
TableRow(
children: <Widget>[
TableCell(
child: Text(''),
),
TableCell(
child: SizedBox(
height:
440, //The clickable region of the button begins to be cut off around 430, and stops altogether by 450
))
],
),
TableRow(children: <Widget>[
TableCell(
child: Text(""),
),
TableCell(
child: TextButton(
onPressed: () => {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Hi Button"))),
},
child: Text("Hi"))),
])
]),
],
),
),
]);
}
What is causing this effect? I am assuming it is some interaction between the visible container and the Table.
Edit: as suggested by #pskink rendered with debugPaintSizEnabled flag which highlights the problem perfectly. However; how would you fix?

Flexible widget didn't work on text widget flutter

I'm trying to use flexible on my text cause it's overflow but for some reason expanded or neither flexible didn't work. But it work on other text widget on different screen. Anyone know why ? How can I fix this ?
return Row(
children: [
/// Ticket Details
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// Ticket Title
Flexible(
child: Text(
ticketData['title'],
style: primaryColor700Style.copyWith(
fontSize: fontSize18,
),
),
),
SizedBox(height: 8),
/// Date Created
Text(
'Created : ' +
DateFormat('d MMM y').format(
DateTime.parse(
ticketData['date_created'].toDate().toString(),
),
),
style: primaryColor400Style.copyWith(
fontSize: fontSize12,
),
),
],
),
/// Urgent Icon
if (ticketData['is_urgent'])
Icon(
Icons.warning_rounded,
size: 35,
color: warningColor,
),
],
);
Wrap the column with flexible
Row(
children: [
Flexible(
child: Column(
children:[
Text(),
]
)
)
]
)
Row takes infinite width, To get available width row for next children you can wrap Expanded/ Flexibile/ fixed width widget. You can check this doc more about.
You can find this from Layout algorithm on Row
Expanded, to indicate children that should take all the remaining room.
Flexible, to indicate children that should share the remaining room but that may by sized smaller (leaving some remaining room unused).

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:
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?
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'),
),
),
],
),
),
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:
View upvote and downvote totals.
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'),
),
),
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.
The 1st Expanded would be laid out with a maxWidth = 100. Since it is an Expanded its width will be 100.
The Flexible widget is also laid out with a maxWidth = 100. But its size could be 50 (and not 100).
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.
Row(
children: <Widget>[
Expanded(
child:Container(
color: Colors.green,
child: const Text('Small text'),
),
),
Expanded(
child: Container(
color: Colors.red,
child: const Text('Small text'),
),
),
]
)

Trying to Understand ConstrainedBox

Flutter Newbie here.
Please refer to this example from Flutter docs Example
I have added just 4 lines to that code. You will find those lines which has comment "Lines Added by me".
But there is no change in the output.
Widget build(BuildContext context) {
return DefaultTextStyle(
style: Theme.of(context).textTheme.bodyText2,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
print(viewportConstraints.minWidth); // Lines Added By me
print(viewportConstraints.maxWidth); // Lines Added By me
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
maxWidth : viewportConstraints.minWidth/2, // Lines Added By me
minWidth : viewportConstraints.minWidth/2, // Lines Added By me
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
// A fixed-height child.
color: const Color(0xffeeee00), // Yellow
height: 120.0,
alignment: Alignment.center,
child: const Text('Fixed Height Content'),
),
Container(
// Another fixed-height child.
color: const Color(0xff008000), // Green
height: 120.0,
alignment: Alignment.center,
child: const Text('Fixed Height Content'),
),
],
),
),
);
},
),
);
}
So I am just playing with that example. And i wanted to see that if i can control the width of containers by providing maxWidth to constrainedBox. But its not working and i want to know reason/concept behind that?
Now in section layout behaviour of container says that "If the widget has an alignment, and the parent provides bounded constraints, then the Container tries to expand to fit the parent, and then positions the child within itself as per the alignment."
Can someone explain me where i am wrong in my understanding ?
From the above ScreenShot it seems that proper(width/2) constraints are not passed to column.

How can I fill whole free place in a column with a children widget with required size property?

I have an UI in Flutter that has a simple circular chart with some text.
This circular chart (https://pub.dev/packages/flutter_circular_chart) has a required size property. So, we must define its size, but in this way it won't be responsive for all UI screen sizes, it does not fit the whole space I'd like to.
So, e.g. I'd like to set its size to also cover the space annotated with blue:
Is it possible to set its size dynamically to fit whole free space in the column?
I tried expaned, fittedbox with double.infinity size parames etc. but neither of them helped.
My code:
Widget _buildChart() {
return Expanded(
child: Container(
color: Colors.green,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
AnimatedCircularChart(
duration: Duration(milliseconds: 0),
key: _chartKey,
size: const Size(140.0, 140.0),
chartType: CircularChartType.Radial,
percentageValues: true,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildText(
'${AppLocalizations.of(context).localize("free")}: $freeCount',
Colors.white),
_buildText(
'${AppLocalizations.of(context).localize("busy")}: $busyCount',
Theme.of(context).buttonColor),
],
)
],
),
),
);
}
Would you be so kind to help me to solve this? How can I make its size responsive? Is it possible at all?
Wrap your AnimatedCircularChart in FittedBox which is further wrapped in Expanded and you don't have to deal with Size anymore. No matter what size you provide, it will always give you the maximum space left.
Expanded( // add this
child: FittedBox( // and add this
child: AnimatedCircularChart(
key: Key("chart_key"),
duration: Duration(milliseconds: 0),
size: Size(1, 1), // no matter even if it is 1, it will take up all remaining space
chartType: CircularChartType.Radial,
percentageValues: true,
initialChartData: data,
),
),
)
Full code:
Widget _buildChart() {
return Expanded(
child: Container(
color: Colors.green,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded( // add this
child: FittedBox( // and add this
child: AnimatedCircularChart(
key: Key("chart_key"),
duration: Duration(milliseconds: 0),
size: Size(1, 1), // no matter even if it is 1, it will take up all remaining space
chartType: CircularChartType.Radial,
percentageValues: true,
initialChartData: data,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text("Free: 14"),
Text("Busy: 31"),
],
)
],
),
),
);
}
Update:
If you are talking about the remaining space above the ring on bigger screen, then it is because of the ring ability to remain circular in shape, so it can't really go beyond that. I have created a small video recording to show you the effect. And I have used size: 1.
Use the LayoutBuilder class for that.
The layoutbuilder class allows you to give a defined height depending on the parent widget constraints. For example you could say that the chart height is 40% of the available height of the parant widget.
For further responsiveness (screen rotation etc.) check out MediaQuery