Flutter 源码阅读 - 三棵树流程分析(一)
日常工作中我们所编写的一个个 Widget,它到底是什么东西、以及它是如何展现在用户面前的? 本系列文章将会通过一些小的案例以及源码来进行分析 Flutter 中 Widget
、Element
、RenderObject
三棵树之间的关系以及它们各自的作用(注意:本系列文章对 Layer
暂不做探讨)。
本篇文章将会通过源码先对他们做一个简单的分类,让读者先留下一个印象。在后续的文章中将会逐渐进行深入分析。
一、 Widget
的分类
Flutter 中是通过 Widget
嵌套来进行构建 UI 的(Flutter 中万物皆 Widget
),我们首先来看下 Widget
的分类。
通过查看 Flutter 源码我们可以得出以上总结,Widget
大致可以分为 RenderObjectWidget
和组合型 Widget
(根据有没有对应的 RenderObject
来进行分类)。
RenderObjectWidget
又可以分为 LeafRenderObjectWidget
、 SingleChildRenderObjectWidget
、 MultiChildRenderObjectWidget
等。
通过下图源码我们可以看出 RenderObjectWidget
抽象类主要包含四个方法:createElement
、createRenderObject
、updateRenderObject
、didUnmountRenderObject
,其中 createElement
和 createRenderObject
为抽象方法,需要子类去实现。
RenderObjectWidgets provide the configuration for [RenderObjectElement]s, which wrap [RenderObject]s, which provide the actual rendering of the application.
通过注释我们可以看出 RenderObjectWidget
主要是为 RenderObjectElement
提供配置,创建 RenderObject
。
组合型 Widget
又可以分为 StatelessWidget
、StatefulWidget
、ProxyWidget
等。这里我们主要主要看下 StatelessWidget
和 StatefulWidget
。
StatelessWidget
主要有 createElement
和 build
方法,其中 createElement
返回了一个 StatelessElement
,build
则为抽象方法,就是我们经常实现的一个方法。
StatefulWidget
主要有 createElement
和 createState
方法,其中 其中 createElement
返回了一个 StatefulElement
,createState
也是一个抽象方法,也是我们我们经常实现的一个方法。通过 StatelessWidget
、 StatefulWidget
与 RenderObjectWidget
的源码进行对比我们发现主要是 RenderObjectWidget
多了 createRenderObject
抽象方法。那么 createElement
和 createRenderObject
主要是做什么的,又有哪些作用呢?在这里先留下一个疑问,后续将会进行讲解。
二、 Element 的分类
通过上面对 Widget
的了解,我们可以看出它主要就是为了创建 Element
而生的。相应的,每一个细分的 xxxWidget
都有对应的 xxxElement
。
比如 StatelessWidget -> StatelessElement
,StatefulWidget -> StatefulElement
,InheritedWidget -> InheritedElement
,LeafRenderObjectWidget -> LeafRenderObjectElement
,SingleChildRenderObjectWidget -> SingleChildRenderObjectElement
,MultiChildRenderObjectWidget -> MultiChildRenderObjectElement
等。
每个 xxxElement
最终都会通过继承 ComponentElement
或 RenderObjectElement
来继承 Element
抽象类。这里与上面讲到的 Widget
相对应,组合型 Widget
对应 ComponentElenent
,RenderObjectWidget
对应 RenderObjectElement
。
通过 Element
抽象类的源码我们可以发现,Element
中持有 Widget
、RenderObject
。
// 简化后的 Element 源码
abstract class Element extends DiagnosticableTree implements BuildContext {
Element(Widget widget)
: assert(widget != null),
_widget = widget;
@override
Widget get widget => _widget!;
Widget? _widget;
RenderObject? get renderObject {
RenderObject? result;
void visit(Element element) {
assert(result == null);
if (element._lifecycleState == _ElementLifecycle.defunct) {
return;
} else if (element is RenderObjectElement) {
result = element.renderObject;
} else {
element.visitChildren(visit);
}
}
visit(this);
return result;
}
}
三、 RenderObject 的分类
通过源码中的注释可以看出 RenderObjectWithChildMixin
是为了渲染单子节点而生,ContainerRenderObjectMixin
是为了渲染多子节点而生,RelayoutWhenSystemFontsChangeMixin
是为了配合系统字体更改而生的。
四、最后
最后附上一张 Widget
、Element
、RenderObject
它们的全图,方便读者进行对比查看。
转载自:https://juejin.cn/post/7169495060097007630