What is the difference between Expanded and Spacer in Flutter? Why Flutter team added Spacer when we already have Expanded?
Both Spacer and Expanded does the same job that is they fill up the remaining space in a widget like Row or Column. Before Spacer, we had to use
Expanded(child: Container())
And which is not very good. With Spacer we only have to use
Spacer()
So, using Spacer, we prevent us from writing more code and it also gives clear indication that we are just using it to fill up the remaining space. Both of them have same property of flex which defaults to 1. The only difference is we don't have child property which makes sense. In fact Spacer is
Expanded(child: SizedBox.shrink());
TL;DR
Spacer()
is equivalent to
Expanded(child: Container())
Expanded makes its child widget occupy space.
Spacer occupies space by itself.
If you look at the implementation of Spacer, you'll see that it's a wrapper around Expanded with a dummy child.
Is Spacer really necessary? Probably not. In an alternate universe, Expanded could have had an optional child argument instead.
Related
So I'm trying to make an app where I have the user fill out a couple form fields and process the information when the user submits the form. My problem is that I can't seem to find out how to make the Form scrollable (because it's long and causes a RenderFlex error). Any scrollable widget I wrap it with still causes a RenderFlex error. The only time it scrolls is when I wrap it with a ListView but it too, causes a RenderFlex error and worst of all, for some reason scrolls back to normal when I try to scroll to the bottom to hit the button to submit. I've already tried most of the solutions in How to scroll page in flutter and Flutter - How to make a column screen scrollable, but none of them seem to work. Here's how the form is structured:
- Form
- Column (List of input fields, crossAxisAlignment = CrossAxisAlignment.start)
- Padding (Input field, top padding of 12)
- Column (Text + input field)
- Align (alignment = Alignment.centerLeft)
- Padding (Left padding 8)
- Text (Field title)
- Padding (Symmetric horizontal padding of 8)
- TextFormField (Text input)
- Seven more input fields with the same structure (Padding > Column > Align > ...)
- Padding (Vertical padding of 64)
- Align (center alignment)
- FractionallySizedBox (for 75% width)
- SizedBox (for fixed height)
- ElevatedButton (Submit button)
- Text (Submit button text)
I hope this is enough information and I'd really appreciate if anyone could help me out with making this form scrollable. Thanks in advance!
The problem is when you use Column without specifying the height it considers the height to be infinite. Try to wrap the first column widget with SizedBox and make use of MediaQuery to determine the screen height and set it as the height parameter for SizedBox.
Now, wrap the Column with a SingleScrollChildView to make it scrollable.
For Example,
SizedBox(
height: MediaQuery.of(context).size.height,
child: SingleScrollChildView(
child: Column(...),
),
),
Lastly, why do you need a second Column for text and input field? Can't you just use the InputDecoration method from TextField() and use the labelText or HelperText
You can use SingleChildScrollView Widget.
You can use SingleChildScrollView and wrap it with a Container widget and provide a certain height to it.
I have a Row with some Containers in it, this causes an overflowed on the right.
How can I make that once a container has overflowed, the next ones go in a new line
I hope I was clear and that someone can answer me.
Thank you :)
Instead of using a Row() widget you need to use a Wrap() widget and make sure to have your Container()'s width not overflowed.
Wrap() widget just do according to what you need right now, it arranges its children in horizontal direction(by default - you can change it though) and if any child overflowed then move that child in new line.
In a column or any widget, when i am trying to use listview.builder it don't execute the code. But when i bundle listview.builder in expanded widget it successfully run. Why it runs in expanded widget not another widget?
in the 1st image Without expand and using shrinkwrap: true my output is like that, but why?
In the 2nd image when I am wrapping my listview.builder in expanded widget it runs successfully, why?
Listview.builder works in Column when you add shrinkwrap property as true. It is because listview and its parent takes different height or size, once you add shrinkwrap property it will get minimized to children height and will work fine. Without shrinkwrap it throw overflow or rendering error.
And when you use it with expanded widget both parent and listview expands to the same height so it working fine with Expanded widget
Let's say I have this Column:
Column(
children: [
Flexible(
flex: 2,
child: Card(
child: Text("Card")
)
),
Flexible(
flex: 3,
child: Column(
children: [
// Buttons
]
)
)
]
)
What I want to achieve is that the Card always has a flex of 2, and only gets smaller if the screen (or parent) is too small to render both the card and the buttons. However, with the code above, the card gets scaled down to its minimum size to contain the text, although there is space at the end of the screen.
Replacing the card's Flexible widget with an Expanded widget would fix this, but as I already said, it will never get smaller then, which will end up in a bottom overflow if the screen gets smaller (or the buttons get bigger).
Is there any way to achieve what I want? Or is this just a limitation of Flutter's rendering system?
Edit: I want to avoid making the screen scrollable.
As you probably already know, Flexible allows its child to expand, but it does not force to do so. Viceversa, we use Expanded to force a child to occupy the remaining column/row.
Here's your options:
Use a Flexible Widget, and exploit its fit property: set it to FlexFit.tight to force it to fill the space (default is FlexFit.loose: the child can be at most as large as the available space, but is allowed to be smaller);
Use an Expanded Widget, since I sense that you want to occupy all the available space, a priori;
Mix these two approaches (Flexible on your Card, Expanded on your Buttons, or vice-versa)
In both cases, if some smaller screens are giving you trouble, consider making some elements scrollable: I don't know how big your Card is, but you could wrap it inside a SingleChildScrollView. Or, if you want try something else, you could make the whole screen scrollable with the same approach (you have to pay attention to that Column, though, as there is infinite height...)
When I start to think about those two components I find myself arguing about why should I use one instead of the other. Some questions that come to my mind:
What are the differences between a Container and SizedBox?
I understand that Container can have other parameters like padding or decoration, but if I will not use those, why should I use a SizedBox instead of a Container?
There are performance differences between them?
Small Update: When used for whitespace, there is now even a linter warning to prefer SizedBox instead of Container. The main advantage seems to be that SizedBox can be const and won't even create a new instance during runtime.
Thanks to the magic of open source, you don't have to guess too much.
Container is basically just a convenience widget which sometimes saves you to nest 4 other widgets. If you pass width/height into the Container:
constraints =
(width != null || height != null)
? constraints?.tighten(width: width, height: height)
?? BoxConstraints.tightFor(width: width, height: height)
: constraints,
Which will result in:
if (constraints != null)
current = ConstrainedBox(constraints: constraints, child: current);
And the ConstrainedBox in effect is pretty much the same as a SizedBox, just more flexible.
A SizedBox will do:
#override
RenderConstrainedBox createRenderObject(BuildContext context) {
return RenderConstrainedBox(
additionalConstraints: _additionalConstraints,
);
}
BoxConstraints get _additionalConstraints {
return BoxConstraints.tightFor(width: width, height: height);
}
ie. It is effectively the same. If you only use Container for width/height there might be a very minor minor negligible performance overhead. but you most certainly will not be able to measure it.. But I would still recommend SizedBox because it's way clearer. imho.
I'd like to add that SizedBox is not only simpler, but it also can be made const, while Container cannot. This may or may not be something you need.
If you need a box with color you cannot use SizedBox. But https://pub.dev/packages/assorted_layout_widgets has the Box widget, which is something between a SizedBox and a Container: You can have color and it can be made const. Note I am the author of this package.
SizedBox() is a widget for giving some constant height or width between two widgets. It does not contain any decorative properties just like color, borderRadius etc.
On the other hand Container() is a widget that any person can modify according to his/her needs.
Just go through properties of both widgets you will see a huge difference between them.
SizedBox and Container creates a RenderObject. The RenderObject lives in the render tree and some computations are performed on it, even if it paints nothing on the screen.
We can do better, we can have a widget which does not create a RenderObject, while being still valid. The Nil widget is the minimal implementation for this use case. It only creates an Element and does nothing while it's building. Because the optimal way to use it, is to call const Nil(), it also comes with a nil constant that you can use everywhere (which is a const Nil()).