在 Flutter 的烘托体系中,Framework 层首先会依据页面界说的元素生成一个个由 Layer 组成的
Scene
目标,接着ui.window
会将这些烘托信息传递到 Engine 层,Engine 层调用底层烘托引擎的接口将这些像素信息制作到屏幕上。
导读
对于开发者而言,Framework 层烘托是最直接接触到的,了解其间的原理可辅助咱们定位问题,写出更高效的代码。这个系列文章将会环绕烘托流程做深入解析,分为以下几部分:
- Flutter Framework 烘托流程剖析(一):开篇
- Flutter Framework 烘托流程剖析(二):Element
- Flutter Framework 烘托流程剖析(三):RenderObject
- Flutter Framework 烘托流程剖析(四):Layer
- Flutter Framework 烘托流程剖析(五):常见问题剖析
Widget
Widget 能够分为三类目标。一类是制作类
,对应RenderObjectWidget
,担任布局和制作,烘托流程中的Layout
、Paint
阶段就与其严密相关;一类是布局类
,对应StatelessWidget
和StatefulWidget
,它更像是一个组织者,经过组合各种RenderObjectWidget
来丰富页面的布局;一类是署理类
,对应ProxyWidget
,它能向子节点提供额定的数据,方便咱们开发时在 Widget Tree 之间传递数据。
制作类
是核心的功能模块,布局类
将这些模块进行堆叠,而署理类
则是在这些模块之间传递数据。
Widget 的要害办法
// code 1.1
// Note: [] 内是类名,后边是办法名。下同!
[Widget] Element createElement();
[Widget] static bool canUpdate(Widget oldWidget, Widget newWidget) {...};
[StatelessWidget] Widget build(BuildContext context);
[StatefulWidget] State createState();
[State] Widget build(BuildContext context);
[RenderObjectWidget] Renderobject createRenderObject(BuildContext context);
经过这些办法,能够得出:
-
Element
和RenderObject
都是从Widget
发生的(经过相应的create
办法); - 所有
Widget
都对应于一个Element
,但只有RenderObjectWidget
才有对应的RenderObject
; - 有两个
build
办法,一个是StatelessWidget
的,别的一个是State
的。但间接或直接都归属于布局类
,究竟像上面说的只有布局类
才会包括子组件并进行组合。
Element
Element 简化了一下分类。一种是制作类
,也就是RenderObjectElement
;另一种是组件类
,也就是ComponentElement
,它囊括了上述Widget
中的布局类
和署理类
。
Element 的要害特点
// code 1.2
[Element] Widget? _widget;
[Element] RenderObject? renderObject;
[Element] Element? _parent;
[Element] Object? _slot;
[ComponentElement] Element? _child;
[SingleChildRenderObjectElement] Element? _child;
[MultiChildRenderObjectElement] List<Element> _children;
Element
持有widget
和renderObject
目标,这很重要,咱们常说的三棵树的构成就与其休戚相关。 事实上Element
在烘托流程中的build
阶段都是至关重要的。一起,它也持有 _parent element
和_child element
,构成一个双向链表
的数据结构。
Element 的要害办法
// code 1.3
// 1. 挂载操作。将自己挂载到树上。
[Element] void mount(Element? parent, Object? newSlot)
// 2. 构建操作。
[ComponentElement] void _firstBuild()
[Element] void rebuild({bool force = false});
[Element] void performRebuild()
[RenderObjectElement] void _performRebuild()
// 3. 更新元素。执行更新或者从头新建
[Element] Element? updateChild(Element? child, Widget? newWidget, Object? newSlot);
[Element] void update(covariant Widget newWidget)
[Element] Elment inflateWidget(Widget newWidget, Object? newSlot);
Element
经过以上这些办法构成一棵树。它在挂载(mount)
自身的时分会触发构建(performRebuild)
行为,在构建
的进程中会经过前面提到的[Widget]build()
办法得到child widget
,经过 updateChild
最终会走到加载(inflateWidget)
,inflateWidget
办法经过child widget
的createElement
办法得到child element
,然后child element
又会执行mount
办法将自己挂载到这棵树上,mount
行为便构成一个循环的操作。
AbstractNode
咱们将在第三、四篇介绍的RenderObject
、Layer
的基类都是AbstractNode
,用来表明一棵树上的笼统节点。
// code 1.4
// 1. 深度。节点的深度标志和更新
[AbstractNode] int get depth => _depth;
[AbstractNode] int _depth = 0;
[AbstractNode] void redepthChild(AbstractNode child) {}
[AbstractNode] void redepthChildren() { }
// 2. 持有。节点的持有者,通常情况下所有节点的被同一个 owner 持有。
[AbstractNode] Object? get owner => _owner;
[AbstractNode] Object? _owner;
[AbstractNode] bool get attached => _owner != null;
[AbstractNode] void attach(covariant Object owner) {}
[AbstractNode] void detach() {}
// 3. 父节点。插入节点或移除节点时会对父节点进行更新。
[AbstractNode] AbstractNode? get parent => _parent;
[AbstractNode] AbstractNode? _parent;
[AbstractNode] void adoptChild(covariant AbstractNode child) {}
[AbstractNode] void dropChild(covariant AbstractNode child) {}
依据以上接口,将一个节点笼统
出了三个特性:深度
、持有者
、父节点
。经过_parent
,便构成了一个树结构。
为什么Element
不承继自AbstractNode
?上面咱们说过,Element
也是一个树结构,AbstractNode
的特性depth
、owner
、parent
在Element
都有同名特点存在,但由于Element
承继了一个用于记载节点信息的类DiagnosticableTree
,而dart
做不到多承继。事实上我以为Element
理应也承继自AbstractNode
,究竟同样身为树结构,只不过需求别的用Mixin
处理一下跟DiagnosticableTree
的关系即可。
总结
作为开篇引言,本文简略的讲了Widget
、Element
、AbstractNode
这几个类,经过类的要害特点和办法介绍了它的作用。关于Element
中树的构建,在下个章节中会具体介绍,咱们常说的Widget Tree
、Element Tree
、RenderObject Tree
其实都是间接经过Element
构建进程中构成的。