This paper mainly introduces the layout of Flutter, combs the relevant knowledge points, and further explains how to layout from practical examples.
1. Introduction
Before introducing the layout of the Flutter, we need to understand some of the layout related features of the Flutter.
1.1 Box Constraints
I think boundary constraints are a little bit more intuitive.
Boundary constraints in The Flutter mean that widgets can determine how they occupy layout space according to specified constraints. Flutter draws on a lot of React stuff, including some layout ideas, but instead of taking layout styles out of it, it uses different widgets to implement different layouts. By embedding the styles into widgets, users can write layouts like building blocks, similar to React, but without the styling.
The advantage of doing this, I think, is probably for uniform rendering. Adding styles makes the layout a lot more complex and reduces performance at the rendering level. Therefore, Flutter adds different types of layout widgets in a larger direction. In small directions, it gives very little customization, limits the layout to a limited scope, and allows the whole render to be unified while completing the layout, speeding up updates and rendering.
However, the disadvantages are equally obvious. There is less flexibility, different layouts are taken away from widgets, and there are so many widgets that people need to know about, which increases the cost of learning.
1.2 Types of Constraints
In Flutter, the widget is rendered by its underlying RenderBox, and the Constraints of the render boundary are given by its parent, and the widget resizes itself within these Constraints. Constraints include minimum and maximum widths and heights, while dimensions are specific widths and heights.
On Android, layouts are limited to three sizes: match_parent, WRap_content, and a specific size. In Flutter, there are also these three constraints.
- As many constraints as possible, such as Center, ListView, etc.
- Follow the constraints of content size, such as Transform, Opacity, etc.
- Specifies size constraints, such as Image, Text, etc.
However, the Flutter does not treat widgets as absolute. These constraints are contained within the widget, unlike Android, which can be specified outside. As a result, some widgets, such as Containers, have different constraints depending on their parameters. Containers are as large as possible by default, but given the size, specific values are preferred. Different widgets may have different conditions, different child widgets, and different constraints. The Flutter limits each widget to a different set of constraints, and the actual layout needs to be taken into account.
Classification of 2.
Many widgets are hard to distinguish by their constraints, and are officially classified by the number of their children.
- The layout of a single child element, including Container, Padding, and so on
18
(the current date is May 25, 2018, I think it will be added later, similar to below); - The layout of children, including Row, Column, and so on
11
Kind of; - Layout helper, such as Listview. Builder, when there are many elements, it is more efficient in this way, similar to Android RecyclerView, with automatic recycling mechanism. This is not strictly a category, and I think there will be more of them.
2.1 the advantages and disadvantages
Most of them are used in daily life, such as Container, Padding, Center, Align, Row, Column, Stack, ListView and so on.
The Flutter provides nearly 30 different layout widgets, again due to the positioning of widgets (not covered here, check out my previous article for more information). Compared to other mobile development platforms, the number of Flutter layout widgets is huge, which is one reason why Flutter has a long learning curve right now.
First, the advantages, unified rendering, update efficiency is higher. However, for the average developer, this is not something that matters. High performance is the most basic capability a platform should provide. Isn’t that what you should provide?
Then talk about the shortcomings, it is still very difficult to master, layout is also very egg pain. Regular layout is ok, when it comes to complex layout, I think this can be achieved, that can be achieved, and finally I don’t know which can be achieved.
2.2 Personal Views
The performance of the Flutter has been optimized by transferring some of the cost of the platform to the developers. However, the overall design concept of the Flutter is very good, and only a big wheel company like Google can do this. However, there is a clear lack of human concern, the interspersed constraints between widgets, and the increase in the number of widgets that the Flutter layout controls can be said to have resulted from the constant patching and subsequent helpers, also to fill in the pits, which the Flutter did not handle very well.
However, everything has a process, I can’t say that the Flutter is not done well, it just seems to be a bit chaotic at the moment, the ideal architecture design, landing, may not be so simple, developers have different needs, with ecology, everything can be said, of course, this process is expected to be very slow.
3. The widget explanation
The custom widgets that we use with Flutter are generally inherited from the StatefulWidget or StatelessWidget (not the only ones), which are the two most commonly used widgets. If the state of a control itself does not change, it will be displayed directly after it is created, without changing its colored value, size, or other properties. These widgets are typically inherited from StatelessWidgets, such as Containers and ScrollViews. If a control needs to dynamically change or correspond to some state, such as click state, color value, content area, etc., it is typically inherited from StatefulWidget, such as CheckBox, AppBar, TabBar, etc. In fact, the difference between the two widgets can be seen simply from the name. Both widgets are inherited from the Widget class.
3.1 the Widget class
The Widget class is very important in the Flutter. The widgets inherited from the Widget class are PreferredSizeWidget, ProxyWidget, RenderObjectWidget, StatefulWidget, and StatelessWidget. Most of the widgets we use on a daily basis are inherited from the Widget class,
Looking at the source code for the Widget class, the internal implementation is very simple, with the following constructor
const Widget({ this.key });
final Key key;
Copy the code
The purpose of this key, as stated above, is to control when replacing widgets in the Widget tree. The Key class is the unique identifier of the Widget, Element, and SemanticsNode, from which the LocalKey and GlobalKey are inherited.
3.2 the State
Before we talk about StatefulWidget, let’s talk about State. State does two things:
- It can be read synchronously at the time the widget is built;
- This may change over the lifetime of the widget.
3.2.1 State Life cycle
The life cycle of State has four states:
- Created: The state-.initState method is called when the State object is created;
- The initialized: when the State object is created, but not yet ready to build, the State. The didChangeDependencies at this time is called;
- Ready: The State object is ready to be built, state. dispose has not been called;
- After defunct: State. Dispose is called, the State object cannot be constructed.
The full life cycle is as follows:
- Create a State object, will call StatefulWidget. CreateState;
- Mounted is associated with a BuildContext.
- Call initState;
- Call didChangeDependencies;
- After the above steps, the State object is fully initialized. Call build;
- DidUpdateWidget is called if needed;
- Hot load calls reassemble if it’s in development mode;
- Deactivate is called if its subtree contains a State object that needs to be removed.
- When Dispose is called, the State object will not be built;
- When Dispose is called,State objects are unmounted and cannot be remounted.
3.2.2 setState
One of the more important methods in State is setState, where the widget is updated when the State is changed. For example, when you click on the CheckBox, you switch between the checked and unchecked states, which you do by changing the state.
Looking at the setState source code, there are some exceptions that will be thrown:
- Null is passed in;
- In the defunct stage;
- The created stage has not yet been mounted.
- Parameter returns a Future object.
After checking for a series of exceptions, the final call code looks like this:
_element.markNeedsBuild();
Copy the code
Inside markNeedsBuild, it is rebuilt on the next frame by marking the element as DIry. As you can see, the setState does not take effect immediately, it just marks the widget, and the real rebuild does not take place until the next frame.
3.3 StatefulWidget and StatelessWidget
The following lists the StatefulWidget and StatelessWidget
A StatelessWidget can be built with multiple different BuildContext, while a StatefulWidget creates a State object for each BuildContext.
3.3.1 StatelessWidget
For StatelessWidget, the build method is called in three cases,
- The widget is inserted into the tree for the first time;
- The parent node of the widget changed the configuration;
- The InheritedWidget dependency changed.
class GreenFrog extends StatelessWidget {
const GreenFrog({ Key key }) : super(key: key);
@override
Widget build(BuildContext context) {
returnnew Container(color: const Color(0xFF2DBD3A)); }}Copy the code
3.3.2 rainfall distribution on 10-12 StatefulWidget
There are two main categories of StatefulWidgets:
- Creating resources in initState and destroying them in Dispose does not depend on InheritedWidget or calling setState. These widgets are basically used as the root of an application or page.
- Use setState or rely on InheritedWidget, which will be rebuilt many times during the business life cycle.
class YellowBird extends StatefulWidget {
const YellowBird({ Key key }) : super(key: key);
@override
_YellowBirdState createState() => new _YellowBirdState();
}
class _YellowBirdState extends State<YellowBird> {
@override
Widget build(BuildContext context) {
returnnew Container(color: const Color(0xFFFFE306)); }}Copy the code
4. The layout
Every page has a different design and there are different layout options for the same page. I don’t think it is realistic to just say how the layout should be. Please refer to the official layout tutorial on Flutter. Next, the author, through a simple page, step by step to disassemble the layout of the process. The whole process basically follows the three steps of disassembly, component encapsulation and specific layout.
4.1 apart
4.1.1 Overall disassembly
According to the design, you can see that the whole is displayed in lines, so the outermost layer is a Column element
- The first behavior header, which involves asymmetrical layout, can be done with a Stack or Row, with a blank widget on the right. You might also use the AppBar and remove the bottom shadow to achieve the same effect;
- The second Row can be viewed as a Row, arranged in two pieces. The right-hand side, which involves stacking, will consider Stack;
- The third row is a bit more complicated, but it’s also shown row by row, so the outermost layer is a Column. The middle part of the text needs to be wrapped according to the number, so consider using Wrap. So just to preview where we’re talking about stacking, think about the Stack implementation;
- The fourth Row can be viewed as a Row, arranged in three pieces;
- The fifth Row can be viewed as a Row, arranged in two pieces.
The spacing between each row can be set using Padding or containers.
Through the analysis of the above step by step, so after, basically have a knowledge of general layout, the outermost controls roughly right (as long as you can, is complexity and efficiency problem), then step by step the dismantling of each row element, if there are repeated or feel part can be encapsulated, on to the next step.
4.1.2 Partial disassembly
The disassembly of each line is roughly in accordance with this idea, so the author will not explain it here.
4.2 Component Encapsulation
For example, the author wanted to encapsulate the fourth line of the display, and thought that the layout might be used in the future, so in this step, you can first pull out a control. MainAxisAlignment and Expanded of the Row are used to achieve this effect, which I will not describe in detail.
After this step, the overall planning design diagram has been, each component also has, the next work is to assemble.
4.3 Layout
Specific layout design to some details, such as spacing (Padding or Container), left, right and center (Align), GestureDetector (GestureDetector), rounded corners (ClipRRect) and other special cases, is basically nested, layer by layer to achieve.
For the actual layout, we used a Scaffold with an AppBar at the top to remove the shadows directly to achieve the effect and 2-5 lines of content for the body. The outermost layer can also be implemented with a Column, which is essentially the same. The running effect is shown below.
4.4 code
Code Github address
5. The latter
I have set up a project on Github, which contains my articles on flutter learning, which will be updated regularly, as well as some learning demo.
6. Reference
- Layout Widgets
- Dealing with box constraints in Flutter
- Overview of Flutter Style and Layout Controls
- widgets library
- Building the layout in the Flutter