Flutter里的三棵树

首先,flutter采用数据驱动UI的设计,当数据变化时重新构建UI。基于这个设计,UI的载体widget设计必然不能像Android的View一样。Android的view承载了数据、重用、位置、渲染所有功能,因此创建一个view的成本很高。flutter的widget设计简单的多,widget树作为第一棵树,只是作为数据的载体,用于描述UI,所以构建成本非常低。位置计算和渲染拆分出来由第三棵树render树处理,第二棵树element树作为widget和render的中间体,主要负责组件重用和更新。

widget树

Widget 是 flutter 体系中最基础的组成部分

1
2
3
4
5
/// Describes the configuration for an [Element].  
///
/// Widgets are the central class hierarchy in the Flutter framework. A widget
/// is an immutable description of part of a user interface. Widgets can be
/// inflated into elements, which manage the underlying render tree.

从 sdk 注释可以看出 widget 是对 element的描述,并且是不可变的。
widget 主要分为 StatefulWidget, StatelessWidget, InheritedWidget 和 RenderObjectWidget。最常见的是 StatefulWidget 和 StatelessWidget。如果组件本身不包含状态,创建完不会发生变化,那么就可以用 StatelessWidget,例如 TextField。

StatefulWidget
TextField -> StatefulWidget
InheritedWidget
MediaQuery -> InheritedWidget
StatelessWidget
Text -> StatelessWidget

RenderObjectWidget
Row -> Flex -> MultiChildRenderObjectWidget -> RenderObjectWidget
SizedBox -> SingleChildRenderObjectWidget -> RenderObjectWidget

element树

widget 和element 是1对1的关系,每个widget 都会有一个对应的element。看Widget 类实现就知道,Widget 类有个createElement()的抽象方法,用于创建element。这个方法会在updateChild()方法中调用。具体分析可以看element 重用。
element 可以分为两种ComponentElement 和RenderObjectElement。故名思义RenderObjectElement适用于绘制的element,而ComponentElement 是用于组合不同的element。
由于widget 和element 是1对1对于的,所以上面分类的4种widget 可以和element 的对应关系如下:
StatefulWidget -> StatelessElement -> ComponentElement
InheritedWidget -> InheritedElement -> ProxyElement -> ComponentElement
StatelessWidget -> StatefulElement -> ComponentElement
RenderObjectWidget -> RenderObjectElement
element 树由Element 类中的_parent对象和visitChildren()方法构成。通过这两者可以实现element 树自上向下或自下而上的遍历。

render树

RenderObject 和RenderObjectElement 一一对应,所以相当于从element 树中提取RenderObjectElement 的部分组成的树(当然很多ComponentElement本身也是由RenderObjectElement 组成的,这部分RenderObjectElement 也会在render树中)。
RenderObject 负责页面最终的布局和绘制,其实RenderObject 和 Android View 比较像,最重要的方法是layout()paint()负责控制组件的布局及绘制。

Author

Lyuku

Posted on

2020-06-15

Licensed under