Flutter源码之三颗树分类
文章目录
注:本文代码基于Flutter SDK 3.13.5
一、Widget的分类
作为一个初学者,我们知道在Flutter中万物皆Widget,这恰恰说明了Widget在Flutter中的一个重要性,那么以Android开发者的角度来看,Flutter中的Widget是否等同于Android中的View呢?或者说Widget能否像Android中的UI控件一样分为ViewGroup、View两种形式呢?比如说,将需要传入child参数的Widget可认为ViewGroup,如Container、Center等,将不需要传入child参数的Widget可认为View,如Text、Icon等等,如此分类是否合理呢?
OK,带着疑问,我们先来看下Widget的部分注释。
|
|
翻译:Widget描述一个Element的配置。Widget是Flutter框架中的中心类层次结构。一个widget是用户界面一部分的不可变描述。Widget可以创建出Element,这些Element管理底层渲染树。
其中“be inflated into”在谷歌翻译中会被翻译为“膨胀为”,但是我认为应该翻译为“创建出”比较合理,因为在Widget源码中有一个抽象的createElement方法,就是用来创建并返回Element对象的。
|
|
现在,我们知道了Widget在Flutter中扮演着一个UI配置的角色,它是不可变的,Widget本身既非视图,也不会直接绘制任何内容。从这一维度上讲,Widget不完全等同于Android中的View,所以将Widget像Android中的UI控件一样分为ViewGroup、View两种形式我认为并不合理。
那么Widget该如何分类呢?我们可以先查看Widget的所有直接子类,比对直接子类之间的区别来进行分类。
选中Widget-》点击AS菜单栏Navigate中的Type Hierarchy选项,就可以输出Widget的继承关系层次结构(使用快捷键呼出也可以,我这里的默认快捷键是F4)。


经过仔细比对Widget直接子类之间的区别,将Widget分类后如下图所示。

如上图所示,根据有无RenderObject大致可以将Widget分为RenderObjectWidget一类和非RenderObjectWidget另一类。
- RenderObjectWidget一类
那么RenderObjectWidget是什么?看下它的部分注释说明。
|
|
翻译:RenderObjectWidget为RenderObjectElement提供配置,RenderObjectElement包装了RenderObject,RenderObject提供应用程序的实际渲染。
到这里已经初步知道这三颗树在Flutter中的作用了,Widget为Element提供配置,Element管理着RenderObject,实际渲染的是RenderObject。
再来看下RenderObjectWidget源码。

由上图可知,RenderObjectWidget抽象类主要包含4个方法:createElement、createRenderObject、updateRenderObject、didUnmountRenderObject,其中createElement和createRenderObject为抽象方法,需要子类去实现,也就是说, RenderObjectWidget不仅要创建Element,也要创建RenderObject。
下面以同样的方式查看RenderObjectWidget继承关系层次结构,又可以将RenderObjectWidget一类分为以下几类。
Widget | 说明 |
---|---|
SingleChildRenderObjectWidget | 为SingleChildRenderObjectElement提供配置,只能传入单个Child的Widget |
MultiChildRenderObjectWidget | 为MultiChildRenderObjectElement提供配置,可以传入多个Child的Widget |
LeafRenderObjectWidget | 为LeafRenderObjectElement提供配置,没有Child的Widget |
RenderObjectToWidgetAdapter | 从RenderObject到Element树的桥梁 |
- 非RenderObjectWidget另一类
非RenderObjectWidget又可以按有无State分为StatefulWidget、StatelessWidget和ProxyWidget等等,我们只重点看下StatefulWidget和StatelessWidget。
首先看下StatefulWidget的部分注释。
|
|
翻译:Widget具有可变状态。
在StatefulWidget中主要有createElement和createState方法,其中createElement方法返回了一个StatefulElement,而createState方法则为一个抽象方法,就是我们经常实现的一个方法。

为什么说StatefulWidget是可变的?这是因为State信息在Widget的生命周期中可能会发生变化。Widget实现者可以确保在状态更改时使用State.setState及时通知State。
至于StatelessWidget,看下它的部分注释。
|
|
翻译:不需要可变状态的Widget。
StatelessWidget主要有createElement和build方法,其中createElement方法返回了一个StatelessElement,而build方法则为一个抽象方法,就是我们经常实现的一个方法。

二、 Element的分类
通过对上面Widget分类的了解,我们可以看出它主要是为了给Element提供配置和创建Element而生的。并且细心点就可以发现,对于上述提到的XXXWidget基本上都有对应的XXXElement,如下:
|
|
那么,Element到底是什么?首先看下Element的部分注释。
|
|
翻译:树中特定位置的Widget实例。
通过查看Element的部分源码我们可以发现,Element中不仅持有了Widget、还持有了RenderObject,从这一角度来讲,Element是Widget与RenderObject之间沟通的桥梁。
|
|
下面以同样的方式查看Element继承关系层次结构,可以发现每个XXXElement基本上是通过继承ComponentElement或RenderObjectElement来间接继承Element,Element分类如下图所示。

三、RenderObject的分类
通过前面的了解,我们知道RenderObject用来渲染的,那么RenderObject是什么呢?看下它的部分注释。
|
|
翻译:渲染树中的对象。RenderObject类层次结构是渲染库存在的核心。
下面以同样的方式查看RenderObject继承关系层次结构,又可以将RenderObject分为以下几类。
RenderObject | 说明 |
---|---|
RenderObjectWithChildMixin | 用于渲染只有一个子对象的泛型mixin |
ContainerRenderObjectMixin | 用于渲染具有多个子对象的泛型mixin |
RenderView | 渲染树的根节点 |
RenderBox | 二维笛卡尔坐标系中的渲染对象 |
RenderSliver | 在视口中实现滚动效果的渲染对象的基类 |
RelayoutWhenSystemFontsChangeMixin | RenderObject的Mixin每当系统字体更改时都会调用systemFontsDidChange |