Flutter Widget渲染流程

339 阅读3分钟

Flutter Widget渲染流程

Flutter将视图数据的组织和渲染抽象为三部分,即 Widget,Element 和 RenderObject。

Widget

Widget 是 Flutter 世界里对视图的一种结构化描述,是控件实现的基本逻辑单位,里面存储的是有关视图渲染的配置信息,包括布局、渲染属性、事件响应信息等,简单的说就是视图的配置信息。

Flutter 将 Widget 设计成不可变的,所以当视图渲染的配置信息发生变化时,Flutter 会选择重建 Widget 树的方式进行数据更新,以数据驱动 UI 构建的方式简单高效。

Element

Element 是 Widget 的一个实例化对象,它承载了视图构建的上下文数据,是连接结构化的配置信息到完成最终渲染的桥梁。一个Widget可能有多个Element实例,如:页面有两个一样的文本,这时候就可以复用Widget 了,同一个Widget就对应多个Element.

Flutter 渲染过程,可以分为这么三步:

  • 首先,通过 Widget 树生成对应的 Element 树;
  • 然后,创建相应的 RenderObject 并关联到 Element.renderObject 属性上;
  • 最后,构建成 RenderObject 树,以完成最终的渲染。 可以看到,Element 同时持有 Widget 和 RenderObject。而无论是 Widget 还是 Element,其实都不负责最后的渲染,只负责发号施令,真正去干活儿的只有 RenderObject。

既然是负责发号施令,为什么要有Element 这个中间层呢?

那是因为Widget的不可变性,在Widget 发生变化的时候,Element层将Widget 树的变化做了抽象,只会将变化的部分同步到了RenderObject上,最大程度的降低了渲染视图树的修改,提高渲染效率。就是在变化的时候,持有该 Widget 的 Element 节点也会被标记为 dirty。在下一个周期的绘制时,Flutter 就会触发 Element 树的更新,并使用最新的 Widget 数据更新自身以及关联的 RenderObject 对象。

RenderObject

而渲染对象树在 Flutter 的展示过程分为四个阶段,即布局、绘制、合成和渲染。 其中,布局和绘制在 RenderObject 中完成,Flutter 采用深度优先机制遍历渲染对象树,确定树中各个对象的位置和尺寸,并把它们绘制到不同的图层上。绘制完毕后,合成和渲染的工作则交给 Skia 完成。

总结

在Flutter 中视图的渲染流程,分由三个部分组成,Widget、Element、RenderObject。 Widget 里面存放的是视图的配置信息,Element 是widget 的实例,通过Element实例得到的配置信息后由RenderObject完成布局和绘制工作,绘制完毕后,合成和渲染的工作则交给 Skia 完成。

几个常见的问题:

  • 同一个 Widget 可以同时描述多个渲染树中的节点,作为配置文件是可以复用的。Widget 和 RenderObject 一般情况是一对多的关系。 ( 前提是在 Widget 存在 RenderObject 的情况。)
  • Element 是 Widget 的某个固定实例,与 RenderObject 一一对应。(前提是在 Element 存在 RenderObject 的情况。)
  • RenderObject 内 isRepaintBoundary 标示使得它们组成了一个个 Layer 区域。
  • 嵌套那么多 Widget ,性能会不会有问题?Widget 只是配置文件,堆叠嵌套了一堆控件,对最终的 RenderObject 而言,可能只是多几个 Offset 和 Size 计算而已。

image.png

参考

flutter填坑之旅(widget原理篇)