I'd like to create the layout shown in the picture below. This shows up fine:
Column( Row, ListView()))
While this renders errors:
Column( Row, Row( ListView(), Column ))
As soon as I replace the inner ListView() with Row( ListView(), Column ), nothing shows up and I get varying error messages, based on various changes I did.
Most often, I see a 'viewport has unlimited horizontal size'.
I guess Listview to be the source of the problem. That said, I'm no aware how to fix it.
Furthermore, I did find various hints on SO, but none fixed the problem.
How do I fix the problem?
Update 1
While the right Column() may be fixed width, the ListView() should take all remaining space of the screen [= availableWidth - WidhtOf(Column())].
put the ListView inside a Container And give it height/width
code
Column(
children: [
Row(
children: [],
),
Row(
children: [
Container(
height: 100,
width: 100,
child: ListView(
children: [
Text(
"1 C/G")
],
)),
Column(
children: [],
)
],
)
],
),
Both Row and Column have a mainAxisSizeparameter where you can set it to MainAxisSize.min so they will take their children's size.
Now, about the ListView, there is a shrinkWrap parameter that makes it so its max size will be its children's size. Another idea might be using a Flexible widget around the ListView, it does almost the same as Expanded, but the difference is: Expanded forces the child to occupy the remaining space, while Flexible allows the children to have any given size smaller than that, and that's because of its fit parameter that by default is FlexFit.loose.
Related
How do you guys solve the following Flutter layout??
I have a screen, where I have to show, as described in the picture: a logo + 3 TextFormFields + 2 buttons + a Container.
Problems:
I need to put all the widgets inside a Column and, the Column inside a SingleChildScrollView so that, when the keyboard pops up, it does not cover the TextFields.
The last widget, the Container, shall take all the remaining screen space on the bottom, but NOT taking more than the screen size. For that, My idea was to use the Expanded widget, so that the Container can expand to the bottom of the screen, but that gives an error:
The following assertion was thrown during performLayout(): RenderFlex children have non-zero flex but incoming height constraints are unbounded.
So I guess my question, in short is, how do I prevent the keyboard to cover the TextFields, while at the same time I force the Container to take all the remaining space on the bottom.
That was my attempt:
SingleChildScrollView(
child: Column(
children: [
Image.asset("assets/images/appLogo.png"),
TextFormField(),
TextFormField(),
TextFormField(),
Row(children: [TextButton(), TextButton()]),
Expanded(child: Container())
],
));
Expanded doesn't know how much size to take. Also the other children don't know their exact size.
Wrap your Image inside a container and give height & width to it. also try wrapping all textfields inside a column or container each.
SingleChildScrollView(
child: Column(
children: [
Container(
width: MediaQuery.of(context).Size.width * 0.4,
height: MediaQuery.of(context).Size.height * 0.2,
child: Image.asset("assets/images/appLogo.png"),
),
Column(
children: [
TextFormField(),
TextFormField(),
TextFormField(),]
)
Row(children: [TextButton(), TextButton()]),
Expanded(child: Container())
],
));
I hope this will work for you.
I try to build layout from picture with no success. How can I do it? (See what I've tried below)
I build Row like this:
final row = Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Item(),
SizedBox(width: _minSpacing),
Item(),
SizedBox(width: _minSpacing),
Item(),
],
);
Works good, but can't downscale content on overflow. So I put this thing inside FittedBox to support downscaling:
final fittedRow = FittedBox(
fit: BoxFit.scaleDown,
child: row,
);
At this point Row stopped to distribute free space between items. It seems FittedBox tries to be as small as possible and don't provide free space for Row. So I also tried to put it inside Container to maybe stretch FittedBox:
Container(
width: double.infinity,
child: fittedRow,
);
But Row still won't spread its children. The best thing I could do, is to set BoxFit.contain - then FittedBox at least start to upscale Row to fill whole screen.
You can use Flexible Widget and assign them flex value.
final row = Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: Item(),flex: 1,),
Flexible(child: Item(),flex: 1,),
Flexible(child: Item(),flex: 1,),
],
);
If you wrap your items with Flexible widget and assign them flex value i think you will get you want exactly, it will set up your items automatically depend on phone's screen
The text inside my Text widget is not wrapping, even when wrapped in a Flexible widget. I found a workaround but it involves wrapping a Column widget inside a Flexible widget which I am not sure is best practice.
I have seen many similar answers online, but none for my exact problem. It is relevant that my text widget in question is nested inside the following hierachy Row -> Column -> Row
A rough idea of how this layout should look:
Here is the original code. When run the text overflows the screen rather than wrapping.
Row(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("top column"),
Row(
children: [
Text("left row"),
Text(
"this is the text that needs to wrap, this is the text that needs to wrap",
),
],
),
],
crossAxisAlignment: CrossAxisAlignment.start,
),
Text("right side"),
],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
);
Here is code that solves my problem, but it involves wrapping both the Text widget AND the outer Column widget in a Flexible widget:
Row(
children: [
Flexible( // added Flexible widget, but doesn't seem correct.
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("top column"),
Row(
children: [
Text("left row"),
Flexible( // added Flexible widget
child: Text(
"this is the text that needs to wrap, this is the text that needs to wrap",
),
)
],
),
],
crossAxisAlignment: CrossAxisAlignment.start,
),
),
Text("right side"),
],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
);
Is there a better way to achieve this wrapping or is enclosing the Column in a Flexible widget a satisfactory approach?
Your approach is right, here's why :
You managed to the problem of the inner Row long text by wrap it into a Flexible,to prevent an overflow in the horizontal axis.This works perfectly if this is your whole tree,but this isn't the case.
Up on your widget tree there is no horizontal constraint limiting the width of children.Column wraps in the vertical axis, so the children of the upper-most Row one with fixed width (Text("right side")) and the other is unbounded one (Column).
When you wrapped the Column with Flexible, it made children bounded horizontally. Another approach would be to use a Container, but it is not the best one as it needs you to give the width before build.
I am trying to create a Card that displays the score in a game. The card will be more complex than this example, but in the middle of the card I want to have a Row. That Row contains two Columns. The first Column contains two Rows. In each of those two Rows is the team name and the score.
Widget build(BuildContext context) {
return Card(
child: Row(
children: <Widget>[
Column(
children: <Widget>[
Row(
children: <Widget>[
Text('Team A'),
Text('100'),
],
),
Row(
children: <Widget>[
Text('Team B'),
Text('100'),
],
),
],
),
Text('15:00'),
],
),
);
}
Now I want t wrap the Text widgets that display the team name in a Expanded. Once I do that I get a long descriptive error that basically says my Row has a parent that does not have a finite width, but it has a child that is asking to expand and these two are in conflict. I get that they are in conflict. How do I fix it? I definitely don't want to give the parent Widget (the Card) a finite width.
It's not 100% clear what you want the scoreboard to look like - this is an instance where a quick mock-up would be a great help.
However, I can tell you why you're getting an exception.
When you wrap your 'Team A' text in an Expanded, during the layout pass flutter gets confused. The top level row has two items, neither of which define any sort of size, so it makes them as large as possible in the cross axis (vertical) and as small as possible in the main axis (horizontal). This means that they delegate their size to their children.
By wrapping 'Team A' in an Expanded, you're basically telling it:
"Hey you, your parent widget is pretty big. I want you to take up all of it that isn't already being used instead of being how big you would normally be."
It responds with
"Sure boss, but I've just checked and none of my parents actually have
a defined size.... so I don't know what to do. Guess I'll just throw an
exception."
The fix is to size the parent, which in this case is the column that contains the two rows (geez, that's confusing).
I think from your description what you want is for that column to take up as much space as possible, so you just have to wrap it in expanded as well. So if you do this, your problem should resolve itself:
Widget build(BuildContext context) {
return Card(
child: Row(
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
Expanded(child: Text('Team A')),
Text('100'),
],
),
Row(
children: <Widget>[
Expanded(child: Text('Team B')),
Text('100'),
],
),
],
),
),
Text('15:00'),
],
),
);
}
That way, the column containing the two rows expands to take all available space during its layout pass. Once the 'Team A' text gets around to trying its layout pass it can simply size itself (horizontally) to that column.
You can then play around with the flex factor to get everything how you want.
Just an FYI - once you start getting lots of nested containers and rows you might want to consider a CustomMultiChildLayout. It's slightly more manual as you need to do the layout calculations yourself, but it might be easier in the long run depending on how complex your scoreboard is.
I am trying to make a widget take up 1/3 the screen regardless of the phone orientation. How do I accomplish this?
I got what I wanted by using a Column and wrapping the contents in Flexible and changing the flex to get the child to take up 1/3 the screen:
new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Flexible(flex: 2, child: new SizedBox()),
new Flexible(flex: 1, child: createTextBox())
]
);
There's a few widgets that might help: AspectRatio, Column/Expanded, and CustomSingleChildLayout in particular. It's hard to give a good answer without knowing exactly what you want to do though.
You should try using Expanded widgets as the children of your row, like so:
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Expanded(
child: yourFirstContentWidget,
),
new Expanded(
child: yourNextContentWidget,
),
new Expanded(
child: yourLastContentWidget,
)
]
)
The Expanded widgets will each try to fill as much space of the row as possible. Since there are three of them, they will have to share the space and you'll end up with each taking up 1/3 of the row.