在flutter
中,一切皆Widget
。无论是显示界面的UI元素,如Text
、Image
、Icon
等;还是功能性组件,如手势检测的GestureDetector
组件、应用主题数据传递的Theme
组件、移除系统组件自带Padding的MediaQuery
组件等。可以说,flutter
界面就是由一个个粒度非常细的Widget
组合起来的。
由于Widget
是不可变的,所以当视图更新时,flutter
会创建新的Widget
来替换旧的Widget
并将旧的Widget
销毁。但这样就会涉及到大量Widget
对象的销毁和重建,从而对垃圾回收造成压力。也因此,flutter
将Widget
设计的十分轻量,并将视图的配置信息与渲染抽象出来,分别交给Element
与RenderObject
。从而使得Widget
只起一个组织者作用,可以将Element
与RenderObject
组合起来,构成一个视图。
1、Widget介绍
前面说过Widget
是一种非常轻量且不可变的数据结构,只起一个组织者作用。那么它是如何轻量的尼?下面我们就从源码来一窥究竟。
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key key;
/// 创建Widget对应的Element对象,Element对象存储了Widget的配置信息
@protected
Element createElement();
/// 判断是否可以更新Widget
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
Widget
是一个抽象类,它只有两个方法:
- createElement:该方法是一个抽象方法,需要在子类实现。顾名思义,该方法主要是创建
Widget
对应的Element
对象。 - canUpdate:该方法主要是判断
Widget
是否可更新。根据Widget
的runtimeType
与key
这两个字段来判断。
由于Widget
可以将Element
与RenderObject
组合成一个视图,但从上面源码我们可以发现,Widget
并没有创建RenderObject
对象的方法,那么它是如何创建RenderObject
对象的尼?其实是通过RenderObjectWidget
的createRenderObject
方法来创建的,此Widget
是一个非常重要的类,如果不直接或间接继承该类,Widget
就无法显示在界面上。下面我们对RenderObjectWidget
源码一窥究竟。
abstract class RenderObjectWidget extends Widget {
...
const RenderObjectWidget({ Key key }) : super(key: key);
/// RenderObjectWidget对应着RenderObjectElement及其子类
@override
RenderObjectElement createElement();
/// 创建一个RenderObject对象
@protected
RenderObject createRenderObject(BuildContext context);
/// 更新renderObject
@protected
void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }
/// 将renderObject从render树中移除
@protected
void didUnmountRenderObject(covariant RenderObject renderObject) { }
}
RenderObjectWidget
是一个继承自Widget
的子类,但它比Widget
多几个方法。
- createRenderObject:创建
RenderObject
对象,在该对象中会将视图数据绘制到不同的图层上。笔者认为它对应着Android中ViewManager的addView方法。 - updateRenderObject:更新
Widget
所持有的RenderObject
对象。笔者认为它对应着Android中Vie