下面是Flutter官网提供的关于三棵树的介绍,比较形象,这里直接摘录了,可以参考原文。
1 2 3 4 5 6 7 8 9
| Container( color: Colors.blue, child: Row( children: [ Image.network('https://www.example.com/1.png'), const Text('A'), ], ), );
|
上面这段代码构建的三棵树如下所示:
在开发调试阶段使用Flutter inspector可以看出实际的Widget树要比代码中描述的层级更深。
先看下Widget的家族:
两外还有如下经常使用的Wiget:
- PreferredSizeWidget继承自Widget,相关子类有AppBar和TabBar;
- LayoutBuilder可以根据parent的布局约束来创建合理的布局;
Element树
先看下Element的家族:
从类图可以看出Element是连接Widget和RenderObject的纽带。
RenderObject树
通常情况下RenderObject是由RenderObjectElement创建的,当Element状态变为unmounted时,要销毁RenderObject(调用RenderObject.dispose)。我们一般不会定义RenderObject的子类,而是使用RenderBox(或者RenderProxyBox),RenderBox采用的是笛卡尔坐标系,如果需要创建不是笛卡尔坐标系的布局,则就需要直接继承RenderObject了。
大部分的 Flutter widget 是由一个继承了 RenderBox 的子类的对象渲染的,它们呈现出的 RenderObject 会在二维笛卡尔空间中拥有固定的大小。 RenderBox 提供了 盒子限制模型,为每个 widget 关联了渲染的最小和最大的宽度和高度。
- RenderParagraph继承自RenderBox,用于渲染文本;
- RenderImage也是继承自RenderBox,用于渲染图片;
- RenderTransform继承自RenderProxyBox,用于在绘制子节点内容前应用变换;
- RenderView是render tree的根节点,直接继承自RenderObject。RenderView只有一个孩子节点RenderBox。
- RenderProxyBoxWithHitTestBehavior继承自RenderProxyBox,我们自定义widget是可以用这个,这个组件允许自定义hit-testing行为,比如HitTestBehavior.deferToChild;
三棵树的生成过程
zenuml
WidgetsBinding.wrapWithDefaultView {
}
WidgetsBinding.scheduleAttachRootWidget {
"异步执行attachRootWidget"
}
WidgetsBinding.attachRootWidget {
new RootWidget
attachToBuildOwner {
RootWidget.attach {
new RootElement
RootElement.assignOwner
BuildOwner.buildScope {
RootElement."callback执行mount" {
_rebuild {
"Element.updateChild"
}
}
"首次build _dirtyElements为空"
}
}
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void runApp(Widget app) { final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized(); binding ..scheduleAttachRootWidget(binding.wrapWithDefaultView(app)) ..scheduleWarmUpFrame(); }
void attachToBuildOwner(RootWidget widget) { final bool isBootstrapFrame = rootElement == null; _readyToProduceFrames = true; _rootElement = widget.attach(buildOwner!, rootElement as RootElement?); if (isBootstrapFrame) { SchedulerBinding.instance.ensureVisualUpdate(); } }
|
Element的根是RootElement,RootElement的mount就是创建Element树的起点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) { if (newWidget == null) { if (child != null) { deactivateChild(child); } return null; }
final Element newChild; if (child != null) { if (child.widget == newWidget) { if (child.slot != newSlot) { updateSlotForChild(child, newSlot); } newChild = child; } else if (Widget.canUpdate(child.widget, newWidget)) { if (child.slot != newSlot) { updateSlotForChild(child, newSlot); } child.update(newWidget); newChild = child; } else { deactivateChild(child); newChild = inflateWidget(newWidget, newSlot); } } else { newChild = inflateWidget(newWidget, newSlot); }
return newChild; }
|
在RootWidget首次执行mount时,走的是第4分支(newWidget不为空,child为空)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| Element inflateWidget(Widget newWidget, Object? newSlot) { try { final Key? key = newWidget.key; if (key is GlobalKey) { final Element? newChild = _retakeInactiveElement(key, newWidget); if (newChild != null) { try { newChild._activateWithParent(this, newSlot); } catch (_) { ...... } final Element? updatedChild = updateChild(newChild, newWidget, newSlot); return updatedChild!; } } final Element newChild = newWidget.createElement(); newChild.mount(this, newSlot);
return newChild; } finally {...} }
|
Element.mount
下面是Element.mount的代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void mount(Element? parent, Object? newSlot) { _parent = parent; _slot = newSlot; _lifecycleState = _ElementLifecycle.active; _depth = _parent != null ? _parent!.depth + 1 : 1; if (parent != null) { _owner = parent.owner; } final Key? key = widget.key; if (key is GlobalKey) { owner!._registerGlobalKey(key, this); } _updateInheritance(); attachNotificationTree(); }
|
Element.mount默认实现是更新_parent/_slot等。除了默认实现外,其他子类Element都会有自己的实现。
ComponentElement
ComponentElement是一个组合类,本身不会产生RenderObject。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @override void mount(Element? parent, Object? newSlot) { super.mount(parent, newSlot); _firstBuild(); }
void _firstBuild() { rebuild(); } void performRebuild() { Widget? built; try { built = build(); } catch (e, stack) { ... } try { _child = updateChild(_child, built, slot); } catch (e, stack) { ... } }
|
SingleChildRenderObjectElement
SingleChildRenderObjectElement继承自RenderObjectElement,会创建自己的RenderObject。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void mount(Element? parent, Object? newSlot) { super.mount(parent, newSlot); _child = updateChild(_child, (widget as SingleChildRenderObjectWidget).child, null); }
void mount(Element? parent, Object? newSlot) { super.mount(parent, newSlot); _renderObject = (widget as RenderObjectWidget).createRenderObject(this); attachRenderObject(newSlot); super.performRebuild(); }
|
MultiChildRenderObjectElement
MultiChildRenderObjectElement也是继承自RenderObjectElement,有多个孩子Element。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @override void mount(Element? parent, Object? newSlot) { super.mount(parent, newSlot); final MultiChildRenderObjectWidget multiChildRenderObjectWidget = widget as MultiChildRenderObjectWidget; final List<Element> children = List<Element>.filled(multiChildRenderObjectWidget.children.length, _NullElement.instance); Element? previousChild; for (int i = 0; i < children.length; i += 1) { final Element newChild = inflateWidget(multiChildRenderObjectWidget.children[i], IndexedSlot<Element?>(i, previousChild)); children[i] = newChild; previousChild = newChild; } _children = children; }
|