flutter渲染三棵树
背景
前几天我们在看ume源码的时候反复提到了renderObject,也简单提了一句renderObject是什么,今天就让我们好好看看flutter渲染的三棵树到底是什么
三棵树的关系(Widget、Element、RenderObject)
看图说话,Widget是用来描述Element的,Element是Widget实例化出来的对象,通过Widget的createElement()方法生成出来的,而RenderObject是用于界面的布局和绘制的,保存了元素的大小,布局等信息,
举个不巧当的例子,Widget(产品经理),element(UI),renderObject(程序员),产品经理将我们的项目蓝图构建出来,描述给UI,UI将产品经理的想法,告诉程序员,程序员根据设计图开发程序,这就是简单的三棵树之间的关系
Widget
Flutter中几乎所有的对象都是Widget,而widget又分为StatelessWidget和StatefulWidget
- StatelessWidget:无中间状态的Widget,一旦创建便不可更改,只能再重新创建
- StatefulWidget:存在中间状态,同时引入了State来存放中间状态,通过调用
state.setState()
进行更新
State
通常一个StatefulWidget会对应一个State,State中有两个常用的属性Widget
、context
Widget:与state相绑定的Widget实例 context:StatefulWidget所对应的BuildContext
abstract class State<T extends StatefulWidget> extends Diagnosticable {
T get widget => _widget;
T _widget;
BuildContext get context => _element;
StatefulElement _element;
@protected
@mustCallSuper
void initState() { ... }
@protected
@mustCallSuper
void reassemble() { ... }
@protected
void setState(VoidCallback fn) {
// 省略掉一些逻辑判断
final dynamic result = fn() as dynamic;
_element.markNeedsBuild();
}
@protected
@mustCallSuper
void deactivate() { ... }
@protected
@mustCallSuper
void dispose() { ... }
@protected
Widget build(BuildContext context);
@protected
@mustCallSuper
void didChangeDependencies() { ... }
}
BuildContext
相信大家对BuildContext
不会陌生,因为不管是StatelessWidget和StatefulWidget都会有个BuildContext
,并且很多组件也需要我们传入BuildContext
,那么BuildContext
到底是什么,其实BuildContext
就是Element的实例
Element
来看下Element的定义
abstract class Element extends DiagnosticableTree implements BuildContext {
Element(Widget widget)
: assert(widget != null),
_widget = widget;
Element _parent;
@override
Widget get widget => _widget;
Widget _widget;
RenderObject get renderObject { ... }
@mustCallSuper
void mount(Element parent, dynamic newSlot) { ... }
@mustCallSuper
void activate() { ... }
@mustCallSuper
void deactivate() { ... }
@mustCallSuper
void unmount() { ... }
以StatefulElement为例:
class StatefulElement extends ComponentElement {
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
...
_state._element = this;
_state._widget = widget;
...
}
State<StatefulWidget> get state => _state;
State<StatefulWidget> _state;
...
@override
Widget build() => state.build(this);
...
}
创建实例时会将state已经赋值给_state,并将element及widget赋值给_state的_element以及_widget,从而使三者相关联起来
关于Element的生命周期我们留作明天再讲,先挖个坑
RenderObject
开篇提到RenderObject是负责渲染的,将所有的RenderObject组成一颗渲染树RenderTree,另外RenderObject的开销是很大的,所以Widget会进行节点的判断发生改变时才会重新创建RenderObject,
//framework.dart
@protected
Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
if (newWidget == null) {
if (child != null)
deactivateChild(child);
return null;
}
Element newChild;
if (child != null) {
assert(() {
final int oldElementClass = Element._debugConcreteSubtype(child);
final int newWidgetClass = Widget._debugConcreteSubtype(newWidget);
hasSameSuperclass = oldElementClass == newWidgetClass;
return true;
}());
if (hasSameSuperclass && child.widget == newWidget) {
if (child.slot != newSlot)
updateSlotForChild(child, newSlot);
newChild = child;
} else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
if (child.slot != newSlot)
updateSlotForChild(child, newSlot);
child.update(newWidget);
assert(child.widget == newWidget);
assert(() {
child.owner._debugElementWasRebuilt(child);
return true;
}());
newChild = child;
} else {
deactivateChild(child);
assert(child._parent == null);
newChild = inflateWidget(newWidget, newSlot);
}
} else {
newChild = inflateWidget(newWidget, newSlot);
}
assert(() {
if (child != null)
_debugRemoveGlobalKeyReservation(child);
final Key key = newWidget?.key;
if (key is GlobalKey) {
key._debugReserveFor(this, newChild);
}
return true;
}());
return newChild;
}
...
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
结语
好了今天的源码查看就到这了, 作为Flutter届的一个小学生,希望大家多多指教,有问题的地方一起讨论
转载自:https://juejin.cn/post/7029655858120228895