Some time ago, I had a brief introduction to xiao CAIWidgetOf whichWidget 是 immutableImmutable, whileWidgetIs how to achieve the update redraw, this cannot leaveElement 和 RenderObject; A brief introduction to the side dishesElementRelevant knowledge;
Element
      Element 是 Widget 在 UIAn instantiated object at a specific location in the tree;UI View 在 ElementA real one is built into the hierarchyElement TreeIs the true view tree structure;ElementAs aWidget 和 RenderObjectBetween coordinators and underWidgetTo complete the operation of adding, deleting and changing nodes;
Source code analysis
Element involves a long source code, xiao CAI only for specific methods and life cycle for learning;
The life cycle
enum _ElementLifecycle {
initial,
active,
inactive,
defunct,
}
Copy the code
The life cycle of an Element consists of initial, active, inactive and defunct.
In view of the way
1. createElement
Element(Widget widget) : assert(widget ! = null), _widget = widget;Copy the code
Create an Element that uses the specified Widget as its configuration. Create an Element by calling Widget.createElement from the Widget as its initial location;
2. mount
@mustCallSuper void mount(Element parent, dynamic newSlot) { ... _parent = parent; _slot = newSlot; _depth = _parent ! = null ? _parent.depth + 1 : 1; _active = true; if (parent ! = null) _owner = parent.owner; if (widget.key is GlobalKey) { final GlobalKey key = widget.key; key._register(this); } _updateInheritance(); }Copy the code
Mount () adds the newly created Element to the specified parent slot tree by calling attachRenderObject.
3. update
@protected Element updateChild(Element child, Widget newWidget, dynamic newSlot) { if (newWidget == null) { if (child ! = null) deactivateChild(child); return null; } if (child ! = null) { if (child.widget == newWidget) { if (child.slot ! = newSlot) updateSlotForChild(child, newSlot); return child; } if (Widget.canUpdate(child.widget, newWidget)) { if (child.slot ! = newSlot) updateSlotForChild(child, newSlot); child.update(newWidget); return child; } deactivateChild(child); assert(child._parent == null); } return inflateWidget(newWidget, newSlot); }Copy the code
UpdateChild is Element’s core method, called whenever a child needs to be added, modified, or deleted. It is used to update elements based on Widget changes and then update the UI tree.
newWidget == null | newWidget ! = null | |
---|---|---|
child == null | Returns null. | Returns new [Element]. |
child ! = null | Old child is removed, returns null. | Old child updated if possible, returns child or new [Element]. |
- If the updated Widget is null, the child node is removed. If the child is not null, the child node is removed.
- If the updated Widget is not null and the current child is null, the new Widget is newly created and the inflateWidget creates child nodes.
- If the updated Widget is not null and the current child is not null and the node exists, child. Widget == newWidget indicates that the child node has not changed, and child.slot! = newSlot Indicates that the child node is moved between siblings, and updateSlotForChild updates the node position. Otherwise, return the child node directly;
- When the updated Widget is not null and the current child is not null, the widget. canUpdate is true, which means that the child node can be modified with the newWidget. Otherwise, remove the child node and create a new child node using newWidget; CanUpdate determines whether the key and runtimeType of the new and old widgets are the same.
4. deactivate
@protected
void deactivateChild(Element child) {
child._parent = null;
child.detachRenderObject();
owner._inactiveElements.add(child); // this eventually calls child.deactivate()
}
Copy the code
DeactivateChild specifies that the Element is in the inactive Element list and removes the render object from the render tree; This method prevents Element from becoming a subclass;
5. activate
@mustCallSuper void activate() { final bool hadDependencies = (_dependencies ! = null && _dependencies.isNotEmpty) || _hadUnsatisfiedDependencies; _active = true; _dependencies? .clear(); _hadUnsatisfiedDependencies = false; _updateInheritance(); if (_dirty) owner.scheduleBuildFor(this); if (hadDependencies) didChangeDependencies(); }Copy the code
Activate () When an Element is rejoined to the tree, the frame removes the Element from the inactive inactive Element list, and the Element calls Activate and adds the Element’s render object to the tree;
6. unmount
@mustCallSuper void unmount() { if (widget.key is GlobalKey) { final GlobalKey key = widget.key; key._unregister(this); }}Copy the code
Unmount () is called when the frame will never be reactivated; In order to avoid repeated creation during the animation execution, when removing a specific Element, the inactive Element will be retained in the last frame of the current animation process. If it has not become active by the end of the animation, unmount() will be called to remove the Element completely.
Corresponding relations between
- Widget.createElement is the initial initialization lifecycle from scratch;
- Mount indicates the transition from initial to Active.
- Update is called only when active is active;
- Deactivate Transitions the life cycle from active to inactive.
- Activate Indicates the lifecycle transition from inactive inactive state to Active state.
- Unmount is the transition from inactive inactive state to defunct inactive state;
Subclasses Element
Element has two subclasses: ComponentElement and RenderObjectElement.
ComponentElement
ComponentElement (StatelessElement/StatefulElement/ProxyElement); Each Element corresponds to the Widget;
StatelessElement
class StatelessElement extends ComponentElement { StatelessElement(StatelessWidget widget) : super(widget); @override StatelessWidget get widget => super.widget; @override Widget build() => widget.build(this); @override void update(StatelessWidget newWidget) { super.update(newWidget); assert(widget == newWidget); _dirty = true; rebuild(); }}Copy the code
StatelessElement is relatively simple, mainly rewrite update() to rebuild() when needed;
StatefulElement
@override
void update(StatefulWidget newWidget) {
super.update(newWidget);
final StatefulWidget oldWidget = _state._widget;
_dirty = true;
_state._widget = widget;
try {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
final dynamic debugCheckForReturnedFuture = _state.didUpdateWidget(oldWidget) as dynamic;
} finally {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
}
rebuild();
}
Copy the code
The StatefulElement corresponds to the StatefulWidget and includes the full Element lifecycle, with State and rebuild() updated when updated;
ProxyElement
abstract class ProxyElement extends ComponentElement ProxyElement(ProxyWidget widget) : super(widget); @override ProxyWidget get widget => super.widget; @override Widget build() => widget.child; @override void update(ProxyWidget newWidget) { final ProxyWidget oldWidget = widget; assert(widget ! = null); assert(widget ! = newWidget); super.update(newWidget); assert(widget == newWidget); updated(oldWidget); _dirty = true; rebuild(); } @protected void updated(covariant ProxyWidget oldWidget) { notifyClients(oldWidget); } @protected void notifyClients(covariant ProxyWidget oldWidget); }Copy the code
ProxyElement is an abstract class that subclasses ParentDataElement and InheritedElement; Update () is called when the Widget is updated; NotifyClients () is called when the old and new widgets have indeed changed;
RenderObjectElement
RenderObjectElement Element corresponds to RenderObjectWidget; RenderObjectElement as an abstract class also inherits all of Element’s lifecycle methods;
Most of the RenderObjectElement only corresponds to a RenderObject is only a child node, such as RootRenderObjectElement/SingleChildRenderObjectElement; But there are also special, such as LeafRenderObjectElement subclass no child nodes, and section MultiChildRenderObjectElement subclasses can have more children;
Element acts as a mediator between Widget and RenderObject; The side dish pair will learn briefly about RenderObject in the next article; Xiao CAI’s understanding of the source code is not deep enough, if there are mistakes, please guide!
Source: Little Monk A Ce