Flutter 的 UI 系统有三棵树, 分别是:
我们看看 Flutter 第一次创建的默认计数器项目:
void main() => runApp(new MyApp()); // *MyApp
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(), // *MyHomePage
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State {
@override
Widget build(BuildContext context) {/*...*/}
}
MyApp 是一个 StatelessWidget
类型的实例.
MyHomePage是一个 StatefulWidget
类型的实例.
StatelessWidget
和 StatefulWidget
都是继承自 Widget 的抽象类.
我们知道 Widget 只是配置信息, 每次 build()
都会新建 widget. 构建 widget 是廉价的, 不会耗费多少资源,因为 Wiget 只是用来保存属性的容器.
在 StatelessWidget
和 StatefulWidget
中, 却找不到跟绘制属性有关的代码, 包括它们的父类里, 因为, 它两都是用于组装其他 Widget 的容器, 而存储绘制信息的, 在它两的最深层子 Widget 中.
Flutter 的 Widget 分为两种:
StatelessWidget
和 StatefulWidget
RenderObjectWidget
包括系统控件和自定义控件, 都是上面三个之一的实现, 而 Widget 类是他们的祖父类, 提供公共的接口作为一层抽象, 不直接使用.
下面我们看看能影响绘制的 widget.
这个网站 列出了 Flutter 所有的 Widget, 在里面找到了继承 RenderObjectWidget
的 Widget:
Opacity 和 Row 都间接继承了 RenderObjectWidget
正如它们的父类也带有后缀名一样.
Opacity 描述了child widget 的透明度, Row 包含了描述了 children widgets 需要水平布局, 这些就属于绘制信息了.
通过查看 Flutter 的基本控件 Text 的源码可以发现, Text 继承了 StatelessWidget, 这就表示了 Text 是由其他控件组成的, 查看 Text 的 build 方法, 发现了 RichText, 而 RichText 继承了 MultiChildRender
, 最底层的 widget 一定是 RenderObjectWidget
, 从布局到具体控件, 一条下来这样, 逻辑就清晰了.
Flutter 的控件, 除了间接继承 RenderObjectWidget
类型的, 那么就一定可以在 build() 方法里找到一个间接继承 RenderObjectWidget
的控件.
Widget 树是一棵对开发者来说的逻辑树, Element树才是真正存在于 Flutter 里的树.
在第一次创建 Widget 的时候,会对应创建一个 Element, 然后将该元素插入树中。如果之后 Widget 发生了变化,则将其与旧的 Widget 进行比较,并且相应地更新 Element。重要的是,Element 被不会重建,只是更新而已。
既然 Widget 有容器和带绘制信息的控件之分, 那么 Element 也是有的.
StatelessWidget 和 StatefulWidget 对应的 Element 继承自 ComponentElement
, RenderObjectWidget 对应 RenderObjectElement
.
/// An [Element] that uses a [StatelessWidget] as its configuration.
class StatelessElement extends ComponentElement {
/// Creates an element that uses the given widget as its configuration.
StatelessElement(StatelessWidget widget) : super(widget);
@override
StatelessWidget get widget => super.widget;
// ...
}
/// An [Element] that uses a [StatefulWidget] as its configuration.
class StatefulElement extends ComponentElement {
StatefulElement(StatefulWidget widget)
: _state = widget.createState(), super(widget) {/*...*/}
@override
Widget build() => state.build(this);
State get state => _state;
State _state;
// ...
}
/// An [Element] that uses a [SingleChildRenderObjectWidget] as its configuration.
/// ...
SingleChildRenderObjectElement(SingleChildRenderObjectWidget widget) : super(widget);
@override
SingleChildRenderObjectWidget get widget => super.widget;
// ...
}
Element 在 Widget 中创建.
RenderObjectWidget
保存了绘制属性, 而真正渲染的工作, 是在 RenderObject
.
abstract class RenderObjectWidget extends Widget {
const RenderObjectWidget({ Key key }) : super(key: key);
@override
RenderObjectElement createElement();
@protected
RenderObject createRenderObject(BuildContext context);
@protected
void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }
@protected
void didUnmountRenderObject(covariant RenderObject renderObject) { }
}
Element
通过 mount
方法插入到 Element Tree 中, RenderObject
的这时候创建.
~
参考资料: [译] Flutter,什么是 Widgets、RenderObjects 和 Elements?