一、Widget
Flutter是移动UI框架,Widget组件是UI的基础。
Widget继承关系图它们都是抽象类,继承Widget,开发中与StatelessWidget、StatefulWidget类打交道最多,继承两者实现自定义Widget。
1,StatelessWidget,状态不会改变的Widget。
abstract class StatelessWidget extends Widget {
const StatelessWidget({ Key key }) : super(key: key);
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
build()是抽象方法,每一个类型Widget都对应一种Element,createElement()方法创建。
2,StatefulWidget,状态会改变的Widget组件,需要指定一个State类,根据状态改变时,setState()方法刷新UI,组件会重新build。
定义抽象方法createState()。
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key key }) : super(key: key);
@override
StatefulElement createElement() => StatefulElement(this);
@protected
State createState();
}
抽象类State<T extends StatefulWidget>,提供初始化initState()方法,刷新setState()方法,抽象方法build(),构造Widget,(和StatefulWidget关联)。
build()返回的Widget和它本身的关系:
本质上是由该Widget对应Element的build()方法触发,通过调用Widget或State的build()方法,并没有将当前Widget和返回Widget建立树关系,而是利用返回Widget,为其构建Element,同时mount()挂载,因此,在Flutter中,真正实现树结构的是Element。
3, RenderObjectWidget,三个子类。
LeafRenderObjectWidget,叶子节点。
SingleChildRenderObjectWidget,只有一个Child,包含一个 final Widget child;
,子类在构造方法初始化child Widget,例如 Center类。
MultiChildRenderObjectWidget,有多个Child,包含一个 final List<Widget> children;
列表,子类在构造方法初始化children数组,例如 Column,Row类。
二、Element
真正的视图树结构
Element(Widget widget)
: assert(widget != null),
_widget = widget;
基类Element构造方法,初始化Element关联的_widget组件。
Element类继承关系不同Widget,createElement()方法,创建不同Element,mount()方法也不同,Widget和Element对应关系。
Widget | Element |
---|---|
StatelessWidget | StatelessElement |
StatefulWidget | StatefulElement |
RenderObjectElement | RenderObjectElement |
LeafRenderObjectWidget | LeafRenderObjectElement |
SingleChildRenderObjectWidget | SingleChildRenderObjectElement |
MultiChildRenderObjectWidget | MultiChildRenderObjectElement |
RootRenderObjectElement,根节点视图。LeafRenderObjectElement,没有子视图,(叶子节点)。
SingleChildRenderObjectElement,仅有一个子视图。
MultiChildRenderObjectElement,有多个子视图。
1,StatelessElement和StatefulElement类
class StatelessElement extends ComponentElement {
StatelessElement(StatelessWidget widget) : super(widget);
@override
StatelessWidget get widget => super.widget;
@override
Widget build() => widget.build(this);
...
}
build()方法,调用关联widget的build()方法,返回Widget。
class StatefulElement extends ComponentElement {
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
_state._element = this;
_state._widget = widget;
}
StatefulElement构造方法,参数StatefulWidget组件,createState()方法,初始化State对象,State关联Element和StatefulWidget,
StatefulElement类的build()方法,调用关联State的build()方法,返回Widget。
@override
Widget build() => state.build(this);
State的build()方法,参数this,(BuildContext类型),其实,Element实现BuildContext。
开发者重写StatelessWidget或State<T extends StatefulWidget>的build()方法,(返回Widget),都是由Element负责调用。
2,ComponentElement的挂载
StatelessElement和StatefulElement类都继承ComponentElement,它们的挂载由基础ComponentElement的mount()挂载方法。
mount的意思是将这个节点挂到树上去。
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
_firstBuild();
}
super.mount()基类Element的挂载方法,即初始化_parent = parent;
,指将该节点指向入参父Element。
调用流程:_firstBuild() == > rebuild() == > performRebuild()。
(performRebuild是Element的抽象类,如下ComponentElement类实现)。
@override
void performRebuild() {
Widget built;
try {
//调用widget的build或state的build。
built = build();
} catch (e, stack) {
}
try {
//将调用inflateWidget()方法,_child:内部的子Element。
_child = updateChild(_child, built, slot);
assert(_child != null);
} catch (e, stack) {
}
}
通过build()方法,创建Widget,根据不同类型Element,Widget或State的build()方法,(即开发重写的即该方法)。
新创建的Widget(built),作为该Element子节点的配置,updateChild()方法,初始化子Element节点,ComponentElement类保存一份Element _child;。
Element基类的inflateWidget(),根据Widget构造Element。
@protected
Element inflateWidget(Widget newWidget, dynamic newSlot) {
final Key key = newWidget.key;
if (key is GlobalKey) {
final Element newChild = _retakeInactiveElement(key, newWidget);
if (newChild != null) {
newChild._activateWithParent(this, newSlot);
final Element updatedChild = updateChild(newChild, newWidget, newSlot);
return updatedChild;
}
}
//调用widget自己重写的createElement()方法
final Element newChild = newWidget.createElement();
//挂载
newChild.mount(this, newSlot);
return newChild;
}
创建的子Element节点挂载mount到自己上,this即内部_parent,Element是树形结构,每一个视图对应Element。
ComponentElement类挂载mount(),将触发build方法,构建widget对象,再去inflateWidget(),为Widget生成Element,挂载,初始化构建Element树。
3,RenderObjectElement子类的挂载
Element类基础mount()方法,将内部_parent设置父视图Element。
SingleChildRenderObjectElement类,有一个子元素。
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
_child = updateChild(_child, widget.child, null);
}
super.mount()挂载,初始化_parent和内部_child元素,根据widget的child,和ComponentElement挂载类似(build方法产生的子Widget),updateChild()方法直接处理子Widget,(widget.child),生成_child元素。
(widget对应SingleChildRenderObjectWidget,内部child Widget。)
MultiChildRenderObjectElement类,有多个子元素。
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
_children = List<Element>(widget.children.length);
Element previousChild;
for (int i = 0; i < _children.length; i += 1) {
final Element newChild = inflateWidget(widget.children[i], previousChild);
_children[i] = newChild;
previousChild = newChild;
}
}
遍历该widget的child数组中每一个widget,通过Element的inflateWidget(),获取每一个子widget的Element,内部保存_children数组(Element)。
任重而道远
网友评论