The author | anders liu, mainland China only Flutter GDE, small JiTuanDui members

In Flutter, everything is a Widget, gesture is a Widget, animation is a Widget, and UI is a Widget. Today we will talk about a special one of the widgets, Container.

1. Introduction

Container is very simple to use at first, but its logic is a bit complicated. I can’t say THAT I fully understand it. Therefore, this article mainly summarizes various articles on the Internet and adds my own understanding

In Flutter, all functions are scattered into single-function widgets, such as Center, Padding, Text, and GestureDetector. They each maintain one function. However, the UI of our commercial apps is very beautiful. To achieve a good layout, we need to nest a lot of layout widgets, so Container comes into being.

A convenience widget that combines common painting, positioning, and sizing widgets.

The official documentation explains why Container is so complex. It is a convenience widget that combines drawing, positioning, and sizing widgets. As far as I know, it can set sizes, background colors, borders, rounded corners, shadows, and gradients. The size of the Container can vary depending on the parent, child, or itself, so we’ll focus on the layout of the Container (size rules, width and height) later.

2. Widget rendering process

Flutter is the render tree structure, first of all, starting from the root node, transmission constraints, from top to bottom until the final leaf node (no children), and leaf nodes according to the constraint to determine their own size, and then returned to the superior nodes size, and then at the next higher level, according to the size of the leaf node to determine your own size, and back at the next higher level, Finally, the root node determines the size. After that, the root node steps down to the position of the children (based on the size and offset of the children and their siblings).

3. Container rendering process

According to the Container, the Container first uses the padding set to surround the child parts, then adds additional constraints on the padding size (if not empty), and then the Container is surrounded by an outer margin. During the drawing process, the Container first applies a transform, then draws decorations to fill the area, then draws sub-components, then foreground decorations, and fills the area.

Decoration and foregroundDecoration are fill configurations. The former is below the subcomponents and the latter is above the subcomponents. You can set fill colors, borders, fill shapes, shadows, gradients, background images, etc.

If the constraints of the Container are limited, a Container without child parts will try to be as large as possible, and if the constraints of the Container are unbounded, it will try to be as small as possible.

A Container that has child components determines its size based on the child components.

4. There is no limit

What are restricted and unrestricted constraints, and what are the various parts?

In Flutter, widgets are rendered by the underlying RenderBox. The parent component provides constraints to the RenderBox. The RenderBox then adjusts its Size with these constraints.

In general, there are three types of boxes that handle constraints:

• As large as possible: Center and ListView, etc

• As large as any sub-component: Transform, Opacity, etc

• Specific size: Image, Text, etc

• Special cases: Row and Column are determined by their given constraints, and Container is determined by arguments to its constructor

However, constraints can sometimes become compact, meaning that it does not leave the rendering box to decide on its own size (for example, the maximum width is equal to the minimum width, which is a fixed value), such as the App Widget, where the constraint is set to a fixed size of the application content (i.e., the entire screen). In Flutter, many widgets, especially those that can only have one child, will pass their constraints to the child. That is, if you have a set of widgets nested in your App’s root render tree, they will be placed one at a time due to tight constraints.

However, some widgets make constraints loose, meaning that maximum constraints remain but minimum constraints are removed, such as Center.

4.1 Unlimited Constraints

• In some cases, the constraints given to widgets are unbounded, or infinite. In other words, the maximum width and maximum height are double.INFINITY.

• A widget that tries to be as big as possible will not work when it encounters unlimited constraints because it does not know how big it should be. In debug mode, exceptions will be thrown.

• The most common cases of having unlimited constraints are embedded in elastic boxes such as rows, columns, or scrollable areas (ListView or other ScrollView subclasses).

It is important to note that the ListView will expand to the parent boundary in the direction of its intersection, such as a list scrolling vertically, and try to be as wide as the parent horizontally. When you embed a scrolling list inside a scrolling list, the scrolling list is going to be as wide as it can be, which is infinitely wide, because scrolling lists are infinitely wide, which is not normal.

In addition, elastic boxes (Row and Column) behave differently under restricted and unrestricted constraints.

• When constrained, they will be as large as possible in their direction.

• In the case of unrestricted constraints, they will accommodate their child components in their direction (enveloping the child components). In this case, you can’t use Expanded in elastic boxes because it will not be possible to determine the size of the parts.

5. Container Layout (Size rules)

The layout of a Container is a bit complicated because it combines the functions of other parts. In short, in order, a Container will:

• Follow alignment rules

• Resize itself for child parts

• Follow widths, heights and constraints

• Then try to make the Container as small as possible.

5.1 Let’s take a look at the explanation of the official documentation (if you don’t understand this explanation, it is a bit wordy) :

• If the Container has no children, no width, and no constraints, and the parent provides unbounded constraints, the Container will be as small as possible.

• If the Container has no child parts and no alignment rules, but provides height, width, or constraints, then the Container will be as small as possible following the width, height, constraints, and parent constraints.

• If the Container has no children, no width, no constraints, and no alignment, but the parent provides constraints, then the Container expands to fit the parent constraints

• If the Container has an alignment rule and the parent provides unlimited constraints, the Container will try to adjust itself to surround the child

• If the Container has an alignment rule and the parent provides constraints, the Container will try to expand to fit the parent, and then place the children within it based on the alignment

• Also, a Container has children, but it has no width, height, constraints, or alignment rules. The Container passes the parent’s constraints to its children, and then adjusts itself to match the children.

• Margin and padding also affect layout, decoration will add padding implicitly (e.g. border).

• The default is as large as possible

5.2 Let’s summarize:

maxWidth maxHeight The constraint With or without subcomponents Layout rules
Have a value Have a value There are limits There is no As large as possible
Have a value There is no value Height is unlimited, width is limited There is no Keep the height as small as possible and the width as wide as possible
There is no value Have a value Height is limited, width is unlimited There is no The height is as large as possible and the width is as small as possible
There is no value There is no value unlimited There is no As small as possible
Will do Will do Will do There are As small as possible to satisfy the constraints

5.3 example

There are no subcomponents, there are constraints, as large as possible ↓

There is no child component, the maximum width of the parent component constraint is the width of the screen, and the maximum height is infinite. The minimum width of its own constraint is 100, and the minimum height is 100, then the height is as small as possible, and the width is as large as the screen width ↓

The maximum constraint of the parent component is the width of the screen. If the parent component has a fixed width of 100, the width is 100. The height of the parent component can be as large as the screen height ↓

There is no constraint set by ourselves, there is a child component, so we wrap the child component ↓

If there are sub-components, the height is 100 and the width covers the sub-components ↓

If the width is set to infinite, the height is set to 100. The width is the constraint screen width of the parent component ↓

If the minimum width and height are set to unlimited, the screen size is ↓

6. Summary

Container should be the most flexible layout widget in Flutter. It is important to use Container wisely. Otherwise, your code will become unreadable and difficult to maintain

7. References

[1]https://juejin.cn/post/6844903669108834311; [2]https://api.flutter.dev/flutter/widgets/Container-class.html [3]https://flutter.dev/docs/development/ui/layout [4]https://flutter.dev/docs/development/ui/layout/box-constraints [5]https://medium.com/jlouage/container-de5b0d3ad184 [6]https://flutterdoc.com/widgets-container-d8eee21ad2f4 [7]https://flutteracademy.com/posts/what-is-a-container-in-flutter/ [8]https://www.youtube.com/watch?v=wj1ZGQ-Jc04 [9]https://www.youtube.com/watch?v=4KVCaP69GV8 [10]https://proandroiddev.com/understanding-flutter-layout-box-constraints-292cc0d5e807


How to analyze the iOS startup time
NNPopObjc: Protocol oriented programming principles in Objective-C
Pecker: Automatic detection of unused code in projects
Guide to Flutter State Management – Provider
5 cool iOS libraries