Widget

flutter中,every is widget,理解起来很容易,我们所使用的显示文字的Text,展示图片的Image,展示位置信息的Padding,都是Widget.

在阅读Flutter源码的,你可能会注意到Widget的定义:

  1. @immutable
  2. abstract class Widget extends DiagnosticableTree {
  3. ...
  4. const Widget({ this.key });
  5. final Key key;
  6. static bool canUpdate(Widget oldWidget, Widget newWidget) {
  7. return oldWidget.runtimeType == newWidget.runtimeType
  8. && oldWidget.key == newWidget.key;
  9. }
  10. ...
  11. }

官方这样讲:

A widget is an immutable description of part of a user interface.

小部件是对用户界面的不可变的描述。

我们注意到左上角有@immutable,这个很重要,窗口小部件中的所有属性都必须为final,一旦实例化,就无法跟更改内部属性,但是事实上,我们的UI不可能一成不变的,因此Flutter如何管理UI的状态呢?

Flutter有三棵树,Widget树、Element树、RenderObjects树,这些树分工不同,将他们组合在一起,来优化UI的各种可能性。

Element是什么

记录一个Widget的位置信息

An instantiation of a [Widget] at a particular location in the tree.

它是树的可变部分,用于管理UI更新和更改,您可以将它看做是管理widget的生命周期的元素。每个元素都引用了一个widget,很简单的。

Flutter 详解(深入了解绘制原理) - 图1

RenderObject是什么

Flutter绘制UI时,它不会查看Widget的树,而是查看RenderObjects,它控制大小,布局并保留用于绘制实际widget的所有逻辑,这就是渲染对象实例化很好性能的原因。

为了更好的展示这三棵树,我们看下面小部件:

  1. class HomeRoute extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return Center(
  5. child: Text('Hello world'),
  6. );
  7. }
  8. }

当我们启动应用时

1.Flutter 将遍历您的窗口小部件并创建窗口小部件树。
2. 与小部件对应,Flutter创建元素树,在其中通过createElement()创建每一个Element对象。
3. 当Element调用createRenderObject()时,将创建每个渲染对象。

如图所示:

Flutter 详解(深入了解绘制原理) - 图2

当我们要改变小部件Text的值,我们看下Flutter Inspector的信息。

更改前:

Flutter 详解(深入了解绘制原理) - 图3

更改后:

Flutter 详解(深入了解绘制原理) - 图4

text中显示的值从4变为5,它的renderObject并未改变。

因为在实例化渲染对象很耗费性能,flutter在这点做了保留,省掉了重复实例化的开销,如果他们具有相同的类型,则无需重新创建渲染对象。我们只需要更新key的值,可以做到重新创建渲染对象。

在实际开发中,一个页面估计至少几十个widget,或者上百个widget,那么对应的elementrenderObject也是数量相等的,因此重新创建整个树是非常消耗性能的,flutter最大程度减小性能浪费,从而获得更佳的UI性能。

参考