“This is the 12th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

background

A few days ago, we mentioned the renderObject repeatedly while looking at the UME source code, and also briefly mentioned what the renderObject is. Today, let’s take a closer look at the three trees that flutter renders

Three tree relationships (Widget, Element, RenderObject)

A Widget is used to describe an Element. An Element is an object instantiated by the Widget and created by the createElement() method of the Widget. A RenderObject is used for layout and rendering of the interface, storing information about the size and layout of the Element .

An unfortunate example is Widget(product manager), Element (UI), and renderObject(programmer). The product manager builds our blueprints and describes them to the UI, and the UI tells the programmer what the product manager thinks, and the programmer develops the program based on the blueprints. This is a simple relationship between three trees

Widget

Almost all objects in Flutter are widgets. Widgets are divided into statelessWidgets and StatefulWidgets

  1. StatelessWidget: A Widget with no intermediate state that cannot be changed once created and can only be recreated
  2. StatefulWidget: Intermediate State exists, and State is introduced to hold intermediate State through the callstate.setState()updated

State

Typically, a StatefulWidget corresponds to a State, which has two commonly used properties, Widget and context

Widget: Widget instance context bound to state: BuildContext corresponding to StatefulWidget

abstract class State<T extends StatefulWidget> extends Diagnosticable { T get widget => _widget; T _widget; BuildContext get context => _element; StatefulElement _element; @protected @mustCallSuper void initState() { ... } @protected @mustCallSuper void reassemble() { ... } @protected void setState(VoidCallback fn) {final dynamic result = fn() as dynamic; _element.markNeedsBuild(); } @protected @mustCallSuper void deactivate() { ... } @protected @mustCallSuper void dispose() { ... } @protected Widget build(BuildContext context); @protected @mustCallSuper void didChangeDependencies() { ... }}Copy the code

BuildContext

I’m sure you’re familiar with BuildContext, because statelessWidgets and StatefulWidgets have BuildContext, and a lot of components need us to pass BuildContext, so what is BuildContext? BuildContext is an instance of Element

Element

Let’s look at the definition of Element

abstract class Element extends DiagnosticableTree implements BuildContext { Element(Widget widget) : assert(widget ! = null), _widget = widget; Element _parent; @override Widget get widget => _widget; Widget _widget; RenderObject get renderObject { ... } @mustCallSuper void mount(Element parent, dynamic newSlot) { ... } @mustCallSuper void activate() { ... } @mustCallSuper void deactivate() { ... } @mustCallSuper void unmount() { ... }Copy the code

Take StatefulElement as an example:

class StatefulElement extends ComponentElement { StatefulElement(StatefulWidget widget) : _state = widget.createState(), super(widget) { ... _state._element = this; _state._widget = widget; . } State<StatefulWidget> get state => _state; State<StatefulWidget> _state; . @override Widget build() => state.build(this); . }Copy the code

When an instance is created, state is assigned to _state, and element and widget are assigned to _element and _widget of _state, thus associating the three

We’ll save the life cycle of Element for tomorrow. Dig a hole

RenderObject

RenderObject is responsible for rendering, and all renderobjects are grouped into a RenderTree. RenderObject is expensive, so the Widget will re-create the RenderObject only when the node judgment changes.

//framework.dart @protected Element updateChild(Element child, Widget newWidget, dynamic newSlot) { if (newWidget == null) { if (child ! = null) deactivateChild(child); return null; } Element newChild; if (child ! = null) { assert(() { final int oldElementClass = Element._debugConcreteSubtype(child); final int newWidgetClass = Widget._debugConcreteSubtype(newWidget); hasSameSuperclass = oldElementClass == newWidgetClass; return true; } ()); if (hasSameSuperclass && child.widget == newWidget) { if (child.slot ! = newSlot) updateSlotForChild(child, newSlot); newChild = child; } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) { if (child.slot ! = newSlot) updateSlotForChild(child, newSlot); child.update(newWidget); assert(child.widget == newWidget); assert(() { child.owner._debugElementWasRebuilt(child); return true; } ()); newChild = child; } else { deactivateChild(child); assert(child._parent == null); newChild = inflateWidget(newWidget, newSlot); } } else { newChild = inflateWidget(newWidget, newSlot); } assert(() { if (child ! = null) _debugRemoveGlobalKeyReservation(child); final Key key = newWidget? .key; if (key is GlobalKey) { key._debugReserveFor(this, newChild); } return true; } ()); return newChild; }... static bool canUpdate(Widget oldWidget, Widget newWidget) { return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key; }Copy the code

conclusion

Ok, today’s source view is over here, as a student of Flutter, I hope you can give me more advice and discuss with me where there are problems