When someone who learns Flutter asks why width:100
your widget is not 100 pixels wide, the default answer is to tell him that the widget is placed in the Center, right? (I don't know the reason, the answer is irrelevant)
never do that
If you do that, they'll come back again and again, asking why something FittedBox
isn't working, why Column
is it overflowing, or IntrinsicWidth
what should be done?
Instead, first tell them that Flutter layouts are very different from HTML layouts (this is probably where they came from), and then ask them to remember the following rules:
Constraints go down. Sizes go up. Parent sets position
If you don't understand this rule, you can't really understand the layout of Flutter, so Flutter development should learn early:
more specifically:
- Widgets get their own Constraints from their parent. Constraints are just a set of 4: minimum and maximum width, and minimum and maximum height.
- The widget then iterates over its own sublist. One by one, the widget tells its children what their constraints are (each child may be different), and then asks each child what size it wants.
- The widget then positions its children one by one (horizontally on the x-axis and vertically on the y-axis).
- Finally, the widget communicates its own size to its parent (within the original limits, of course).
For example, if a composite widget like you contains a column with some padding, and you want to lay out its two children like this:
The negotiation looks like this:
- Widget : "Hey Parent, What Are My Limitations?"
- Parent : "Your width must be between
80
to300
pixels and your height must be between30
to85
pixels." - Widget : "Well, since I want
5
a padding of pixels, my child can be at most290
a pixel wide and75
a pixel high." - Widget : " Hey first child, your width must be
0
between290
2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
75
- First Child : "Okay, then I want wide
290
pixels, high20
pixels." - Widget : "Well, since I want to place my second child below the first, my second child is only left with the
55
height in pixels." - Widget : "Hey dick, your width must be
0
between290
to and your height must be0
between55
to." - Second child : "OK, I want wide
140
pixels, high30
pixels." - Widget : "Good. My first child's position is
x:5
sumy:5
, and my second child's position isx:80
sumy:25
." - Widget : "Hey Parent, I've decided that my dimensions will be
300
pixels wide by60
pixels tall."
1. Restrictions
Due to the layout rules mentioned above, Flutter's layout engine has several important limitations:
- A widget can only determine its own size within the constraints just given by its parent. This means that a widget usually cannot have any size it wants .
- A widget cannot know or determine its own position on the screen , because it is the widget's parent that determines the widget's position.
- Since the parent's size and position are in turn dependent on its own parent, it is impossible to precisely define the size and position of any widget without considering the entire tree.
- If a child wants a different size than its parent, and the parent doesn't have enough information to tell the other, the child's size may be ignored. Be specific when defining alignment .
1.1. Examples
The following are 29 examples for the above, please read it slowly, and you will have a better understanding of Contraints after reading.
1.1.1, Example 1
Container(color: red)
Screen is Container
the parent of , which enforces being Container
exactly the same size as the screen.
So Container
will fill the screen and paint it red.
1.1.2, Example 2
Container(width: 100, height: 100, color: red)
The red one Container
wants to 100x100
, but it can't because the screen forces it to be exactly the same size as the screen.
So the container fills the full screen.
1.1.3, Example 3
Center(child: Container(width: 100, height: 100, color: red),
)
The screen is forced Center
to be exactly the same size as the screen, so Center fills the screen.
Center
Tell Container
it to be any size it wants, but not larger than the screen. Now Contaiiner
it can be 100x100
.
1.1.4, Example 4
Align(alignment: Alignment.bottomRight,child: Container(wiidth: 100, height: 100, color: red)
),
This differs from the previous example, which uses Align
instead of Center
.
Align
Also tell Container
it can be any size it wants, but it won't center it if there is empty space Container
. Instead, it will Container
snap to the bottom right corner of the available space.
1.1.5, example 5
Center(child: Container(width: double.infinity, height: double.infinity, color: red)
)
The screen is forced Center
to be exactly the same size as the screen, so Center
it fills the screen.
Center
Tell Container
it to be any size it wants, but not larger than the screen. Container
Wants to be infinitely large, but since it can't be larger than the screen, it can only fill the screen.
1.1.6, Example 6
Center(child: Container(color: red),
)
The screen is forced Center
to be exactly the same size as the screen, so Center
it fills the screen.
Center
Tell Container
it to be any size it wants, but not larger than the screen. Since Container
there are no children and no fixed size, it decides to be as big as possible, so it fills the entire screen.
But why Container
was it decided this way? Simply because it was Container
a design decision by those who created the widget. It may be created differently, and you'll have to read Container
the documentation to understand how it behaves, depending on the situation.
1.1.7, Example 7
Center(child: Container(color: red,child: Container(color: green, width: 30, height: 30)),
)
The screen is forced Center
to be exactly the same size as the screen, so Center
it fills the screen.
Center
Tells red Container
it can be any size it wants, but no larger than the screen. Since red Container
has no size but has a subcontainer, it decides to be the same size as its subcontainer.
Red Container
tells its children that it can be any size it wants, but not bigger than the screen.
The child is a green one Container
and it wants to be 30 x 30
. Given that red Container
itself is the same size as its child, it 30 x 30
is also invisible to red because green Container
completely covers the red container.
1.1.8, Example 8
Center(child: Container(padding: const EdgeInsets.all(20.0),color: red,child: Container(color: green, width: 30, height: 30)),
)
Red Container
resizes itself to the size of its children, but it takes its own padding into account. So it is also 30 x 30
plus padding. Because of the padding, the red courseware and the green Container
are the same size as in the previous example.
1.1.9, Example 9
ConstrainedBox(constraints: const BoxConstraints(minWidth: 70,minHeight: 70,maxWidth: 150,maxHeight: 150,),child: Container(color: red, width: 10, height: 10)
)
You might guess Container
it has to be between 70 and 150 pixels, but you'd be wrong. Only imposes additionalConstrainedBoox
constraints on those received by its parent .
Here, the screen is forced to ConstrainedBox
be exactly the same size as the screen, so it tells its child Container
to also take the size of the screen, thereby ignoring its constraint parameter.
1.1.10, Example 10
Center(child: ConstrainedBox(constraints: const BoxCoonstraints(minWidth: 70,minHeight: 70,maxWidth: 150,maxHeigght: 150,),child: Container(color: red, width: 10, height: 10)),
)
Now, Center
the allowed ConstrainedBox
size does not exceed the screen size. ConstrainedBox
Imposes additional constraints on its constraints
arguments to its children .
Contrainter
Must be between 70 and 150 pixels. It wants to have 10 pixels, so it ends up with 70 (the minimum).
1.1.11, Example 11
Center(child: ConstrainedBox(constraints: const BoxConstraints(minWidth: 70,minHeight: 70,maxWidth: 150,maxHeight: 150,),child: Container(color: red, width: 1000, height: 1000)),
)
Center
The allowed ConstrainedBox
size does not exceed the screen size. ConstrainedBox
Additional constraints on the parameter are imposed on its children.
Container
Must be between 70 and 150 pixels. It wants to have 1000 pixels, so it ends up with 150 (max).
1.1.12, Example 12
Center(child: ConstrainedBox(constraints: const BoxConstraints(minWidth: 70,minHeight: 70,maxWidth: 150,maxHeight: 150,),child: Container(color: red, wiidth: 100, height: 100)),
),
Center
The allowed ConstrainedBoox
size does not exceed the screen size. ConstrainedBox
Imposes additional constraints on its constraints
arguments on its children.
Container
Must be between 70 and 150 pixels. It wants 100 pixels, and that's how big it is because it's between 70 and 150.
1.1.13, Example 13
UnconstrainedBox(child: Container(color: red, width: 20, height: 50)
)
The screen is forced UnconstrainedBox
to be exactly the same size as the screen. However, UnconstrainedBox
allow its child Container
to be any size it wants.
1.1.14, Example 14
UnconstrainedBox(child: Container(color: red, width: 4000, height: 50),
)
Screen forces UnconstrainedBoox
the exact size of the screen, while UnconstrainedBox
letting its children Container
be any size it wants.
Unfortunately, in this case, Container
the width of is 4000px and is too large to fit UnconstrainedBox
, so UnconstrainedBox
the very dreaded "overflow warning" is displayed.
1.1.15, Example 15
OverflowBox(minWidth: 0.0,minHeight: 0.0,maxWidth: double.infinity,maxHeight: double.infinity,child: Container(color: red, width: 4000, height: 50)
)
Screen forces OverflowBox
the exact size of the screen, while OverflowBox
allowing its child Container
to be any size it wants.
OverflowBox
Similar to UnconstrainedBox
; except that it won't show any warning if the child doesn't fit in the space.
In this example, Container
the width of is 4000 pixels, which is too large to fit OverflowBox
, but OverflowBox
just displays as much as possible without warning.
1.1.16, Example 16
UnconstrainedBox(child: Container(color: Colors.red, width: doouble.infinity, height: 100)
)
This won't render anything, you'll see an error in the console.
UnconstrainedBox
Allows its children to be of any size, but its children are containers of unlimited size.
Flutter cannot render infinite size as it throws an error with the following message: BoxConstraints forces an infinite width
.
1.1.17, Example 17
UnconstraintedBox(child: LimitedBox(maxWidth: 100,child: Container(color: Colors.red,width: double.infinity,height: 100,),),
)
You won't get an error here anymore, because when LimitedBox
is UnconstrainedBox
given infinity; it's about to pass a max-width of 100 down to its children.
If you UnconstrainedBox
swap out to Center
a widget, LimitedBox
its limit is no longer applied (since its limit is only applied when it gets infinite constraints), and Container
the width of the widget can grow beyond 100.
This explains the difference between LimitedBox
and .ConstrainedBox
1.1.18, Example 18
const FittedBox(child: Text('Some Example Text.'),
)
The screen is forced FittedBox
to be exactly the same size as the screen. Text has some natural width (also known as its intrinsic width), which depends on the amount of text, font size, etc.
FittedBox
Arbitrary size is allowed Text
, but when Text
told its size FittedBox
, FittedBox
scales Text
until it fills all available width.
1.1.19, Example 19
const Center(child: FittedBox(child: Text('Some Example Text.'),),
)
But what happens if you FittedBox
put it inside a widget? Any size is allowed , up to screen size.Center
Center
FittedBox
FittedBox
It then resizes itself according to the text, and makes the text be whatever size it wants. Since FittedBox
and Text
have the same size, no scaling occurs.
1.1.20, Example 20
const Center(child: FittedBox(child: Text('This is some very very very large text that is too big to fit a regular screen in a single line.')),
)
But FittedBox
what happens if the text is too large to fit the screen while inside the center widget?
FittedBox
Trying to size itself according to the text, but it can't be larger than the screen. It then assumes the screen size to make it fit the screen too.
1.1.21, Example 21
const Center(child: Text('This is some very very very large text thass is too big to fit a regular screen in a single line.')
)
However, if you remove FittedBox
, Text
it takes its largest width from the screen and breaks the line to fit the screen.
1.1.22, Example 22
FittedBox(child: Container(height: 20.0,width: double.infinity,color: Colors.red,),
)
FittedBox
Only bounded widgets (with non-infinite width and height) can be scaled. Otherwise, it won't render anything and you'll see an error on the console.
1.1.23, Example 23
Row(children: [Container(color: red, child: const Text('Hello!', style: big),Container(color: green, child: const Text('Goodbye!', style: big),],
)
The screen is forced Row
to be exactly the same size as the screen.
Like one UnconstrainedBox
, Row
doesn't impose any constraints on its children, but lets them be whatever size they want. Row
They are then placed side by side, any extra space left blank.
1.1.24, Example 24
Row(children: [Container(color: red,child: const Text('This is a very long text that ''won\'t fit the line.',style: big,),),Container(color: green, child: const Text('Goodbye!', style: big))],
)
Since Row
no constraints are imposed on its children, the children are likely to be too large to fit in the Row
available width, as in UnconstrainedBox
, Row
an "overflow warning" is displayed.
1.1.25, Example 25
Row(children: [Expanded(child: Center(child: Container(color: red,child: const Text('This is a very long text that won\'t fit the line.',style: big,),),),),Container(color: green, child: cont Text('Goodbye!', style: big))],
)
When a Row
child of a widget is wrapped in a Expanded
widget, Row
it will no longer let the child define its own width.
Instead, it defines the expanded width in terms of the other children, and only then, the expanded widget forces the original child to have the expanded width.
In other words, once you use Expanded
, the original child's width becomes irrelevant and is ignored.
1.1.26, Example 26
Row(children: [Expanded(child: Container(color: red,child: const Text('This is a very long text that won\'t fit the line.',style: big,),),),Expanded(child: Container(color: green,child: const Text('Goodbye!',style: big,),),),],
)
If Row
all children of the widget are contained within Expanded
the widget, each Expanded
has a size flex
proportional to its parameter, only then each Expanded
widget enforces the width its children have Expanded
.
In other words, Expanded
the preferred width of its children is ignored.
1.1.27, Example 27
Row(children: [Flexible(child: Container(color: redmchild: const Text('This is a very long text that won\'t fit the line.',style: big,),),),Flexible(child: Container(color: green,child: const Text('Goodbye!',style: big,),),),],
)
The only difference if you use Flexible
instead is that hi allows its children to have the same or smaller width than itself, while forcing its children to have the exact same width as itself. But both ignore the child's width when resizing itself.Expanded
Flexible
Flexible
Expanded
Expnanded
Expanded
Flexible
注意:这意味着不可能按比例扩展`Row`子元素的大小。当您使用`Expanded`或`Flexible`时,`Row`要么使用确切的子宽度,要么完全忽略它。
1.1.28, Example 28
Scaffold(body: Container(color: blue,child: Column(children: const [Text('Hello!'),Text('Goodbye!'),],),),
)
The screen is forced Scaffold
to be exactly the same size as the screen, so Scaffold
it fills the screen. Scaffold
Tell Container
it to be any size it wants, but not larger than the screen.
注意:当一个小部件告诉它的孩子它可以小于某个尺寸时,我们说这个小部件向它的孩子提供松散的约束。稍后会详细介绍。
1.1.29, example 29
Scaffold(body: SizedBox.expand(child: Container(color: blue,child: Column(children: const [Text('Hello!'),Text('Goodbye!),],),),),
)
If you want Scaffold
the child to Scaffold
be exactly the same size as itself, you can use SizedBox.expand
a child that wraps it.
注意:当一个小部件告诉它的孩子它必须有一定的大小时,我们说这个小部件向它的孩子提供了严格的约束。
2. Tight constraints and loose constraints
It's common to hear that certain constraints are "tight" or "loose," so it's worth understanding what that means.
Strict constraints offer a possibility, exact size. In other words, a tight constraint's maximum width is equal to its minimum width, and its maximum height is equal to its minimum height.
If you go to Flutter
the box.dart
documentation and search for BoxConstraints
the constructor, you'll find the following:
BoxConstraints.tight(Size size): minWidth = size.width,maxWidth = size.width,minHeight = size.height,maxHeight = size.height;
If you revisit example 2 above, it tells us that the screen forces red Container
to be exactly the same size as the screen. Container
Of course screen does this by passing strict constraints to .
On the other hand, loose constraints and set a max width and height, but keep the widget as small as possible. In other words, loosely constrained minimum width and height are both zero:
BoxConstraints.loose(Size size): minWidth = 0.0,maxWidth = size.witdhminHeight = 0.0,maxHeight = size.height;
If you revisit example 3, it tells us to center to make the red container smaller, but not larger than the screen. Container
Of course, the center does this by passing loose constraints to . Ultimately, Center
the real purpose of a is to convert the tight constraints it gets from its parent (the screen) into the loose constraints of its children ( Container
).
3. Learn specific widgets and layout rules
Knowing the general layout rules is necessary, but not sufficient.
Each widget has a lot of latitude in applying the common rules, so there's no way to know what a widget will do just by reading its name.
If you try to guess, you will most likely guess wrong. You can't know exactly how a widget behaves unless you read its documentation or study its source code.
Layout source code is often complex, so it's best to just read the documentation. However, if you decide to explore the layout source code, you can easily find it using the IDE's navigation capabilities.
- Find a column in your code and navigate to its source code. To do this
Android Studio
,IntelliJ
usecommand+B (macOS)
or orcontrol+B (Windows/Linux)
. You will be taken tobasic.dart
the document . Since isColumn
expandedFlex
, please navigate to theFlex
source code (alsobasic.dart
in ). - Scroll down until you find a method
createRenderObject()
called . As you can see, this method returns aRenderFlex
. ThisColumn
is the render object for . Now navigate to the source codeRenderFlex
of the , which will take you toflex.dart
the file. - Scroll down until you find a method
performLayout()
named . Here's how to do the layout for the columns.
at last
Recently, I also sorted out a JavaScript and ES note, a total of 25 important knowledge points, and explained and analyzed each knowledge point. It can help you quickly master the relevant knowledge of JavaScript and ES, and improve work efficiency.
Friends in need, you can click the card below to receive and share for free