Widget:存放渲染内容、它只是一个配置数据结构,创建是非常轻量的,在页面刷新的过程中随时会重建。
其中Widget根据功能可以分为三类:
- 组合类
StatelessWidget/StatefulWidget:比如我们常见的Container就是一个组合类的控件,它主要负责组合封装多个其他负责绘制的原子组件。
- 代理类
inheritedwidget:它的父类是ProxyWidget,顾名思义。简单来说,InheritedWidget 的作用是向它的子 Widget 有效地传播和分享数据,当 InheritedWidget 作为一个Parent Widget时,它下面的Widget tree的所有Widget都可以去和 InheritedWidget 发生数据传递和交互。当数据发生改变时,一部分控件需要 rebuild,另外的控件不需要 rebuild 的时候,可以使用 InheritedWidget。
- 绘制类
RenderObjectWidget:RenderObjectWidget会负责创建出负责实际渲染的RenderObject对象,RenderObject负责实际的layout()和paint()。后期有空,我会手动写一个RenderObject。
Element: 是分离 WidgetTree 和真正的渲染对象的中间层,可以看成flutter的骨架。 Widget 用来描述对应的Element 属性,同时持有Widget和RenderObject,存放上下文信息,通过它来遍历视图树,支撑UI结构。
其中Element可以根据功能分成两大类:
- 组合类
ComponentElement:主要包括如下 StatelessElement / StatefulElement / ProxyElement 子类;其中各Element都是与 Widget 对应的。
- 绘制类
RenderObjectElement:RenderObjectElement对应的是RenderObjectWidget。
RenderObject用于应用界面的布局和绘制,负责真正的渲染,保存了元素的大小,布局等信息。
当应用启动时 Flutter 会遍历并创建所有的 Widget 形成 Widget树,通过调用 Widget 上的 createElement() 方法创建每个 Element 对象,形成 Element 树。最后调用 Element 的 createRenderObject() 方法创建每个渲染对象,形成一个 RenderObject 树。
如何通过Widget更新Element:
Element/ComponentElement:
单个Element时候通过updateChild方法更新;
大致归纳一下,如下表:
| 标题 |
newWidget == null |
newWidget != null |
| child == null |
Returns null. |
Returns new [Element]. |
| child != null |
Old child is removed, returns null. |
Old child updated if possible, returns child or new [Element]. |
RenderObjectElement:
多个Element时候通过updateChildren方法更新;
该函数的主要职责如下:
- 复用能复用的子节点,并调用updateChild对子节点进行更新。
- 对不能更新的子节点,调用deactivateChild对该子节点进行失效。
我们注意到updateChild如果old child是空或者无法update就需要inflateWidget;
我们从源码看看创建方法inflateWidget():
逻辑非常简单,创建一个element,然后mount到当前element。
RenderObject#
RenderObjectWidget会调用createElement,创建出RenderObjectElement,
然后RenderObjectWidget会调用createRenderObject,创建出RenderObject,
然后通过[RenderObjectElement.mount]方法,将RenderObject挂载为RenderObjectElement._renderObject属性。从此可以看出,Element是连接Widget和RenderObject的桥梁。