The preface

Flutter has also been in development for some time. Today, I will talk about the structural relationships among Widgets, Elements, and RenderObjects.

The three trees

  • The Widget tree is responsible for configuration information, and this is where we write our code.
  • The RenderObject tree is the rendering tree that calculates the layout and draws. The Flutter engine renders based on this tree.
  • The Element tree acts as an intermediary, managing the generation of RenderObjects and updates from widgets.

As you can see from the figure above, there is a one-to-one relationship between the widget tree and the Element tree nodes, with each widget having its own Element. RenderObject trees, however, have nodes only for widgets that need to be rendered.


Widget

The interface we normally write with widgets in declarative form is known as the Widget tree, which is the first tree to be introduced. Let’s take a look at the Widget structure:

  • Widgets come in two types

Widgets are classified from a rendering perspective into renderable and non-renderable widgets. Common statelessWidgets and StatefulWidgets are non-renderable widgets.

  • Internal structure of widget

As shown above:

  1. Each widget is providedcreateElementMethod, which each widget will eventually convert toElement;
  2. The widget is triggeredbuildThe timing of the method is particularly frequent,canUpdateMethods to maintainElement reuse mechanism. When true is returned, reuse the old Element;
  3. Only renderable widgets (subclassesRenderObjectWidget) provide generationRenderObjectThe method of

Element

Corresponding to the classification of widgets, elements distinguish whether they are renderable or not, with the following inheritance:

As we know from the figure above, StatefulElement calls the widget.creatEstate method in its constructor and assigns _state to its widget object. This is when the statefuleWidget createState method is called.

Key points: Analysis of Element’s internal structure (observe its members and methods from left to right)

summarize

  1. Element holds an external Widget object.
  2. Element provides a method for obtaining the RenderObject(get renderObject). Start by walking through the child node until you find itRenderObjectElementRenderObjectElement Provides the ability to generate RenderObjects.]
  3. RenderObjectElement is calledwidget.createRenderObject(this)generateRenderObject
  4. The core method mount() ‘
  1. componentElementThe main function of the mount method is to perform build (depending on type)widget.build.state.build)
  2. renderObjectElementThe mount method of RenderObject is used to generate renderObjects
  3. Called when Element creation is completemount, the call sequence ismount -> _firstBuild -> reBuild -> performRebuild -> build
  4. Element.markNeedsRebuild will eventually reBuild

RenderObject

[RenderObject member structure]

Member methods:

  1. ParentData: Assigned by the parent, the parent RenderObj stores data related to the child RenderObj in the parentData of the child element. In the Stack layout, the RenderStack would store the offset data of the child in the parentData of the child (see the toy implementation).

  2. The Layout () method takes two arguments, constrains, which is the size limit of the parent node to the child node. ParentUsesSize Indicates whether the parent node relayouts simultaneously when the local node layout changes.

  3. _relayoutBoundry: Assign in the Layout () method. When parentUsesSize is false, _relayoutBoundry = this (the current RenderObject) means that its size does not affect the size of parent. Otherwise, _relayoutBoundry = = (parent! as RenderObject)._relayoutBoundary;

  4. MarkNeedsLayout (): The RenderObject is reconfigured when an Element is marked as dirty by calling markNeedsBuild().

Start with itself and iterate through the parent until the RenderObject that is relayoutBoundry is found. Then mark it as dirty and rebuild.

void markNeedsLayout() { ... Omit if (_relayoutBoundary! = this) { markParentNeedsLayout(); } else { ... Omit}}Copy the code
  1. performResize(): in the Layout method, only thesizedByParentIs called only when true.
  2. performLayout(): is called in the Layout method, which fires each time a Layout is invoked

What does setState do in State?

  • The first step: the State setState ()
  • The second step: _element markNeedBuild ()
  • The third step: mark dirty = true
  • The fourth step: readerObject markNeedLayout ()