1.Widget概念
- 字面意思就是 装饰物/小部件,在Flutter中几乎所有的对象都是一个 widget。
- Widget 的功能是“描述一个UI元素的配置信息”(所谓的配置信息就是 Widget 接收的参数,比如对于 Text 来讲,文本的内容、对齐方式、文本样式都是它的配置信息)。
- 与原生相比,原生开发中的“控件”通常只是指UI元素,Flutter 中的 widget 的概念更广泛,它不仅可以表示UI元素,也可以表示一些功能性的组件如:用于手势检测的
GestureDetector
、用于APP主题数据传递的Theme
等等。
2.Widget中的接口
Widget
类本身是一个抽象类。其中最核心的就是定义了createElement()
接口,在 Flutter 开发中,我们一般都不用直接继承Widget
类来实现一个新组件,相反,我们通常会通过继承StatelessWidget
或StatefulWidget
来间接继承widget
类来实现。
Widget源码如下:
// 不可变的
abstract class Widget extends DiagnosticableTree {
const Widget({
this.key });
final Key? key;
Element createElement();
String toStringShort() {
final String type = objectRuntimeType(this, 'Widget');
return key == null ? type : '$type-$key';
}
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
bool operator ==(Object other) => super == other;
int get hashCode => super.hashCode;
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
...
}
3.Flutter中的四棵树
- Widget 树
- Element 树
- Render 树(渲染树)
- Layer 树
既然 Widget 只是描述一个UI元素的配置信息,那么真正的布局、绘制是由谁来完成的呢?Flutter 框架的处理流程是这样的:
- 根据 Widget 树生成一个 Element 树。(Element 树中的节点都继承自
Element
类) - 根据 Element 树生成 Render 树。(渲染树中的节点都继承自
RenderObject
类) - 根据渲染树生成 Layer 树,然后上屏显示。(Layer 树中的节点都继承自
Layer
类)
真正的布局和渲染逻辑在 Render 树中,Element 是 Widget 和 RenderObject 的粘合剂,可以理解为一个中间代理。
我们通过一个例子来说明,假设有如下 Widget 树:
Container( // 一个容器 widget
color: Colors.blue, // 设置容器背景色
child: Row( // 可以将子widget沿水平方向排列
children: [
Image.network('https://www.example.com/1.png'), // 显示图片的 widget
const Text('A'),
],
),
);
注意,如果 Container 设置了背景色,Container 内部会创建一个新的 ColoredBox 来填充背景,相关逻辑如下:
if (color != null)
current = ColoredBox(color: color!, child: current);
而 Image 内部会通过 RawImage 来渲染图片、Text 内部会通过 RichText 来渲染文本,所以最终的 Widget树、Element 树、渲染树结构如下图所示:
这里需要注意:
- 三棵树中,Widget 和 Element 是一一对应的,但并不和 RenderObject 一一对应。比如
StatelessWidget
和StatefulWidget
都没有对应的 RenderObject。 - 渲染树在上屏前会生成一棵 Layer 树,这个会在后面原理篇再介绍,目前只需要记住以上三棵树就行。
4.StatelessWidget
4.1 源码
abstract class StatelessWidget extends Widget {
/// Initializes [key] for subclasses.
const StatelessWidget({
Key? key }) : super(key: key);
/// 重写了 widget 类的 createElement()方法,返回了StatelessElement
StatelessElement createElement() => StatelessElement(this);
Widget build(BuildContext context);
}
StatelessWidget
相对比较简单,它继承自widget
类,重写了createElement()
方法:
StatelessElement createElement() => StatelessElement(this);
StatelessElement
间接继承自Element
类,与StatelessWidget
相对应(作为其配置数据)。
StatelessWidget
用于不需要维护状态的场景,它通常在build
方法中通过嵌套其他 widget 来构建UI,在构建过程中会递归的构建其嵌套的 widget 。
我们看一个简单的例子:
class Echo exte