渲染流程

UI渲染流程
UI渲染流程

Weight

Weight 在Flutter 中是必不可少的存在,翻译过来是控件的意思,Flutter中的每一种都是一个Weight。
Widget里面存储了一个视图的配置信息,包括布局、属性等待。所以它只是一份轻量的,可直接使用的数据结构。在构建为结构树,甚至重新创建和销毁结构树时都不存在明显的性能问题。

而对于渲染问题,并不是由 Weight 直接管理,而是通过State这个对象来管理状态。

1
2
3
4
5
6
7
8
9
10
11
12
/// If you wish to associate mutable state with a widget, consider using a
/// [StatefulWidget], which creates a [State] object (via
/// [StatefulWidget.createState]) whenever it is inflated into an element and
/// incorporated into the tree.

/**
* Widget会被填充到Element,并由Element管理底层渲染树。
* Widget本身没有可变状态(所有的字段必须是final)。
* 如果想要把可变状态与Widget关联起来,可以使用StatefulWidget,
* StatefulWidget通过使用StatefulWidget.createState方法创建State对象,
* 并将之扩充到Element以及合并到树中;
*/

可以看到, Weight是不可变的,如果要使它成为可变状态,就不得不提到Element

Element

Widget 和 Element 之间是一对多的关系 。实际上渲染树是由 Element 实例的节点构成的树,而作为配置文件的 Widget 可能被复用到树的多个部分,对应产生多个 Element 对象。

打开Element类,在里面发现了 Element 的两个重要属性widgetrenderObject

1
2
3
4
5
6
7
8
9
10
11
12
RenderObject get renderObject{
RenderObject result;
void visit(Element element){
assert(result == null);
if(element is RenderObjectElement)
result = element.renderObject;
else
element.visitChildren(visit);
}
visit(this);
return result;
}

也就是说Element同时持有了Widgets和RenderObject。那Element的作用就比较明确了,Element作为中间件来分离控件树和渲染对象。

RenderObject

官方定义:An object in the render tree.渲染树中的一个对象。从其名字,我们可以很直观地知道,它就是负责渲染的工作,实际上,所有的布局、绘制和事件响应全都由它负责,开发复杂视图时我们可能经常需要与之打交道。
而它又是由 Element 的子类 RenderObjectElement 创建出来的,RenderObject 也会构成一个 Render Tree,并且每个 RenderObject 也都会被保存下来以便在更新时复用,Render Tree构建的数据会被加入到 Engine所需的 LayerTree中,Engine通过 LayerTree进行视图合成并光栅化,提交给 GPU。

那么三者关系很明确了:
配置文件 Widget 生成了 Element,而后创建 RenderObject 关联到 Element 的内部 renderObject 对象上,最后Flutter 通过 RenderObject 数据来布局和绘制。

一共有几颗树