Flutter 入门 - Widget -- Element -- RenderObject
Widget
为什么需要自己写 build 方法
- 某些 widget 会生成 RenderObject
- 每一个 Widget 都会生成 Element 实例
- 生成 Element 实例的时候会调用 mount 方法
- statfulWidget、statelessWidget
extents
ComponentElement - ComponentElement: mount -> _firstBuild -> rebuild -> performRebuild -> build
- RenderObjectElement: mount -> _widget.createRenderObject
组件Widget
statfulWidget、statelessWidgetextents
ComponentElement 不会生成 RenderObject
- Container
- Text
- 自己手写的 Widget
statfulWidget
如果是一个StatefulWidget,则创建出来的是一个StatefulElement
我们来看一下StatefulElement的构造器:
- 调用widget的createState()
- 所以StatefulElement对创建出来的State是有一个引用的
- 而_state又对widget有一个引用
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
....省略代码
_state._widget = widget;
而调用build的时候,本质上调用的是_state中的build方法:
Widget build() => state.build(this);
创建流程
ComponentElement: mount -> _firstBuild -> rebuild -> performRebuild -> build
非组件 Widget
Padding
- 创建Element: RenderObjectElement
- RenderObjectElement: mount -> _widget.createRenderObject
- 渲染Widget: 生成RenderObject
Widget 继承链
Padding -> SingleChildRenderObjectWidget -> RenderObjectWidget -> Widget
Element 继承
RenderPadding -> RenderShiftedBox -> RenderBox -> RenderObject
Element
大量的 widget 被重复创建和销毁,属于不稳定的,那谁来维持整个程序的渲染稳定呢,Element! Element 是 Widget的实例,是在树中详细的位置
在每一次创建Widget的时候,会创建一个对应的Element,然后将该元素插入树中。
- Element保存着对Widget的引用;
在SingleChildRenderObjectWidget中,我们可以找到如下代码:
- 在Widget中,Element被创建,并且在创建时,将this(Widget)传入了;
- Element就保存了对Widget的应用;
@override
SingleChildRenderObjectElement createElement() => SingleChildRenderObjectElement(this);
在创建完一个Element之后,Framework会调用mount方法来将Element插入到树中具体的位置:
mount方法
在调用mount方法时,会同时使用Widget来创建RenderObject,并且保持对RenderObject的引用:
- _renderObject = widget.createRenderObject(this);
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
_renderObject = widget.createRenderObject(this);
assert(() {
_debugUpdateRenderObjectOwner();
returntrue;
}());
assert(_slot == newSlot);
attachRenderObject(newSlot);
_dirty = false;
}
但是,如果你去看类似于Text这种组合类的Widget,它也会执行mount方法,但是mount方法中并没有调用createRenderObject这样的方法。
- 我们发现ComponentElement最主要的目的是挂载之后,调用_firstBuild方法
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
assert(_child == null);
assert(_active);
_firstBuild();
assert(_child != null);
}
void _firstBuild() {
rebuild();
}
RenderObject
创建过程小结
Widget只是描述了配置信息:
- 其中包含createElement方法用于创建Element
- 也包含createRenderObject,但是不是自己在调用
Element是真正保存树结构的对象:
- 创建出来后会由framework调用mount方法;
- 在mount方法中会调用widget的createRenderObject对象;
- 并且Element对widget和RenderObject都有引用;
RenderObject是真正渲染的对象:
- 其中有
markNeedsLayout
performLayout
markNeedsPaint
paint
等方法
参考
转载自:https://juejin.cn/post/7000776333043171359