After 30 examples, I understood the layout of the Flutter

Study the most avoid blind, no plan, fragmentary knowledge can not be strung into a system. Where did you learn, where did you forget? I can’t remember the interview. Here I have sorted out the most frequently asked questions in the interview and the core pieces of knowledge in the Flutter framework. There are about 20 articles to analyze. Welcome to pay attention and make progress together. Flutter framework.png

Welcome to the public account: Offensive Flutter or Runflutter, which collects the most detailed guide to advance and optimize Flutter. Follow me and get my latest articles ~

Introduction:

UI Principles:

1. Why not use setState()?

2. The interviewer asked me about the life cycle of State. What should I say

3. Layout constraint principle of Flutter

4. Actual Flutter drawing process

After reading this article, you will learn: How do the various controls of Flutter implement layout


The introduction

It all started with thisFantastic website (In-depth understanding of Flutter layout constraints)”, which provides 30 examples of weird layouts that have opened my eyes to the world (30 of which are pretty unmartial!!). There’s something like thissuch

And then there’s this

I have to say it does cover a lot of scenes! But for a lazy person like me with a short memory, reading 30 examples is too much! Cost! Strength! ! And then forget it!! In fact, there’s a large probability that it won’t happen exactly the same way. So I was wondering, what’s the rationale behind this so I don’t have to go through 30 examples again and again? Which brings us to today’s topic: the layout of the Flutter

If you get more than 50 likes in this issue, add a more issue (detailed analysis of 15 representative examples) is coming! The most detailed analysis of 15 examples gives you a thorough understanding of the principles of Flutter layout


Start: A macro look at the classification of the Flutter components

OnMeasure (),onLayout(),onDraw(), onMeasure() and onDraw(). But the UI concept of Flutter is different from this. First of all, in the component system of Flutter, not all widgets will be rendered to the final page. The whole Widget can be divided into three categories: combination, proxy, and drawing. –

The StatelessWidget and StatefulWidget that we use most often are just controls that compose the class, they don’t actually draw, and almost all of the UI that we see on the screen will eventually be implemented with RenderObjectWidget. RenderObjectWidget has a createRenderObject() method that generates the RenderObject object, which is actually responsible for the actual layout() and paint(). For example, the most commonly used Container component is simply a composite class control that encapsulates several atomic components responsible for drawing. For a more detailed look at RenderObjectWidget take a look at the layout principles of Flutter in depth. It’s very well written


Appetizer: The rendering process for RenderObject

So how does RenderObject render when I’ve been using setState() incorrectly? , the key to rendering the Flutter lies in the drawFrame() method

void drawFrame() {
  // Build () has been completed before
  pipelineOwner.flushLayout();
  pipelineOwner.flushCompositingBits();
  pipelineOwner.flushPaint();
  renderView.compositeFrame(); // this sends the bits to the GPU
  pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
}
Copy the code

The whole process is divided into three stages: build(), Layout (), and paint(). The build() method is implemented by the composite class and proxy class widgets, and Layout () and paint() are implemented by the RenderObject. The layout() method is usually implemented by the ViewGroup, which specifies the location of the child control. So his child nodes are only concerned with drawing.

Layout () in Flutter is more closely understood as Measure (!! This is very important to understand, not to use native thinking to learn), its main function is to calculate the size and position offset of the control itself. The calculation here is a process of passing constraints from the top node and returning measurements from the bottom

The measurement result, which is easy to understand, is the actual width and height of a control. And what is a constraint?


What’s the Constraints

Constraint Constraints is a layout protocol in Flutter. There are two major layout protocols in Flutter: BoxConstraints and Silverconstraints. For non-sliding controls such as Padding, Flex, and so on, BoxConstraints are commonly used.

  BoxConstraints({
    this.minWidth,
    this.maxWidth,
    this.minHeight,
    this.maxHeight,
  });
Copy the code

It seems obvious that in a box constraint, only the maximum width and minimum height of the child control are limited. After I scrounged through almost every layout principle article on the web, this constraint can be summarized as follows. First of all, the constraints can be divided into two categories according to the maximum and minimum values

  • Tight: When Max and min values are equal, a defined width and height value is passed to the subclass.
const BoxConstraints.expand({
    double width,
    double height,
  }) : minWidth = width ?? double.infinity,
       maxWidth = width ?? double.infinity,
       minHeight = height ?? double.infinity,
       maxHeight = height ?? double.infinity;
Copy the code

This constraint is used in two main ways

A in the Container, when the Container child = = null && | | (constraints = = null | |! Constraints. IsTight)). The other ModalBarrier, which we’re not familiar with, is nested in a Route, so every time we push a new Route, the default is that the new page fills the screen.

  • Loose constraint: When Max and min are not equal, then the constraint on the subclass is a range, which is called loose constraint.
BoxConstraints.loose(Size size)
    : minWidth = 0.0,
      maxWidth = size.width,
      minHeight = 0.0,
      maxHeight = size.height;
Copy the code

This layout is used in the Scaffold we most use, so that Scaffold delivers a loose constraint on the sub-layout.


Fun: to name a few chestnuts

With the basic concepts above in mind, let’s take a look at how to analyze some scenarios. When we want to know what the layout process of a control is like, we can refer to:

  • Find a Column in your code and follow up to its source code. To do this, use Command +B (macOS) or Control +B (Windows/Linux) in (Android Studio/IntelliJ). You’ll jump to the basic.dart file. Since Column extends Flex, navigate to the Flex source code (also in basic.dart).
  • Scroll down until you find a method called createRenderObject(). As you can see, this method returns a RenderFlex. This is the render object for Column, and now navigate to the RenderFlex source code in the Flex.dart file.
  • Scroll down until you find the performLayout() method, which performs the column layout.

In accordance with this method, we tried to analyze a few interesting chestnuts. If you get more than 50 likes in this issue, add a more issue (detailed analysis of 20 examples)

Case 1 (from Example 1)

If we return to a red Container, it will fill the entire screen. First of all Container is aCombination of the classThe Widget is not responsible for rendering. Check out his build method, which in this case returns three layers of RenderObjectRenderDecoratedBox.RenderLimitedBox.RenderConstrainedBox

All three classes inherit fromRenderProxyBox, this class is mixed inRenderProxyBoxMixin, the layout method is inside:

 @override
  void performLayout() {
    if(child ! =null) {
      child.layout(constraints, parentUsesSize: true);
      size = child.size;
    } else{ performResize(); }}Copy the code

In fact, from the name of this class, we know that this is a proxy class rendering object, if it has children, it will put its parent constraintsconstraintsPass to the node, and then use the size of the child node as its own. So the outermost layerRenderDecoratedBoxWhat is the constraint on theta. And we actually mentioned earlier that in tight constraints,BoxConstraints.expandIs used on a Route, so each page fills the screen by default. This constraint just keeps going downBut at the bottomRenderConstrainedBoxRewrite theperformLayoutmethods

@override
  void performLayout() {
    if(child ! =null) {
      child.layout(_additionalConstraints.enforce(constraints), parentUsesSize: true);
      size = child.size;
    } else{ size = _additionalConstraints.enforce(constraints).constrain(Size.zero); }}Copy the code

It’s pretty much the same thing, except for RenderConstrainedBox we can add the constraint information _additionalConstraints, Looking at the Container’s build method shows that the constraint is BoxConstraints. Expand in this case, which is also taken into account when it comes to layout. Because RenderConstrainedBox has no more children so let’s go

size = _additionalConstraints.enforce(constraints).constrain(Size.zero); /// Return the new box constraint that respects the given constraint and is as close to the original constraint as possible. BoxConstraints enforce(BoxConstraints) {return BoxConstraints(minWidth: minWidth.clamp(constraints.minWidth, constraints.maxWidth), maxWidth: maxWidth.clamp(constraints.minWidth, constraints.maxWidth), minHeight: minHeight.clamp(constraints.minHeight, constraints.maxHeight), maxHeight: maxHeight.clamp(constraints.minHeight, constraints.maxHeight), ); }Copy the code

The key is to enforce this method. Here he takes the constraint from the page (Max =min= screen width) so that no matter what constraint you add to the page _additionalConstraints he returns a constraint (Max =min= screen width). And this constraint is passed down again

Finally, when the Container is rendered, it fills the entire screen!

Case 2 (from Example 9)

Example 1 adds a constraint on the outer layer and sets its own height on the inside. You might expect the Container to be between 70 and 150 pixels in size, but no, it still fills the entire screen. Let’s look at the structure of the Render treeSo the whole tree structure looks like this, so let’s go step by step. First the outermost layerConstrainedBoxReceiving a tight constraint from the page (Max =min= screen width), the calculation uses the above calculation method to get the same constraint, and then the constraint is passed down to the same situation as in case 1


conclusion

1. Widgets can be roughly divided into three types: combination class, proxy class, and drawing class

2. Almost all the UI we see on screen will eventually be implemented with RenderObjectWidget. RenderObjectWidget has a createRenderObject() method that generates the RenderObject object, which is actually responsible for the actual layout() and paint().

3. The Container component is simply a composite control that encapsulates several atomic components responsible for drawing.

4, the layout() function is mainly to calculate the size and position of the control itself

5. The whole layout process is the process of passing values up and down constraints

6. There are two kinds of box constraints:

  • Tight: When Max and min values are equal, a defined width and height value is passed to the subclass.
  • Loose constraint: When Max and min are not equal, then the constraint on the subclass is a range, called loose constraint

One-sentence summary:


The last

Writing is not easy to welcome attention like, this issue if more than 50 likes, add more (15 examples of detailed analysis)!! Here we come! The most detailed analysis of 15 examples gives you a thorough understanding of the principles of Flutter layout

Reference article:

Juejin. Cn/post / 689701… Juejin. Cn/post / 684490… Blog.csdn.net/weixin_4345…