在Flutter中,Widget、Element、State和RenderObject是构建UI界面的核心概念。它们之间的关系是通过递归创建和管理的。
递归创建的过程如下:
- 创建根Widget:在Flutter应用程序中,首先创建一个根Widget,通常是一个MaterialApp或CupertinoApp。这个根Widget作为应用程序的入口点,它可以包含其他子Widget。
- 构建Widget树:根Widget通过调用其build()方法来构建自身及其子Widget。在build()方法中,可以创建和配置其他Widget,并返回一个新的Widget树。
- 创建Element:在根Widget的build()方法中,Flutter会为根Widget创建一个Element,这个Element作为根元素。然后,根Widget会递归地构建其子Widget,并为每个子Widget创建相应的Element。
- 更新和重建:如果在根Widget的状态发生更改时,例如用户交互触发了某个操作,Flutter会通知相关的Element更新。这会导致相应的Widget被重新构建,并生成新的Element。如果某个Widget的属性发生了变化,也会触发相应的Element更新和重建。
- 渲染树:Element构建完成后,Flutter会将所有Element组成的树转换为渲染树。渲染树是Flutter的内部表示,它描述了如何将Widget渲染为屏幕上的像素。
- 布局和绘制:渲染树中的每个节点都与一个RenderObject关联,它负责计算布局和绘制操作。RenderObject负责测量Widget的大小和位置,并将绘制命令发送给底层渲染引擎。
这样,通过递归地创建Widget、Element和RenderObject,Flutter可以构建出完整的UI界面,并在需要时更新和重建特定的部分。这种递归的方式确保了UI的一致性和高效性。
下面是一些相关的类的核心实现代码:
- Widget(部件):Widget是Flutter UI的构建块,它描述了用户界面的一部分。Widget是不可变的,意味着一旦创建,就不能更改它的属性。当需要更新UI时,创建一个新的Widget并替换旧的Widget。
@immutable
abstract class Widget extends DiagnosticableTree {
@protected
@factory
Element createElement();
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
StatelessElement createElement() => StatelessElement(this);
StatefulElement createElement() => StatefulElement(this);
ParentDataElement<T> createElement() => ParentDataElement<T>(this);
InheritedElement createElement() => InheritedElement(this);
LeafRenderObjectElement createElement() => LeafRenderObjectElement(this);
SingleChildRenderObjectElement createElement() => SingleChildRenderObjectElement(this);
MultiChildRenderObjectElement createElement() => MultiChildRenderObjectElement(this);
Element createElement() => throw UnimplementedError();
- Element(元素):Element是Widget在UI树中的实例。每个Widget都对应一个Element,它负责管理Widget的生命周期、维护与其他元素的关系,并持有与该Widget实例相关的状态。
class StatefulElement extends ComponentElement {
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
state._element = this;
state._widget = widget;
}
@override
Widget build() => state.build(this);
State<StatefulWidget> get state => _state!;
State<StatefulWidget>? _state;
@override
void reassemble() {
if (_debugShouldReassemble(_debugReassembleConfig, _widget)) {
state.reassemble();
}
super.reassemble();
}
@override
void _firstBuild() {
try {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
final Object? debugCheckForReturnedFuture = state.initState() as dynamic;
} finally {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
}
state.didChangeDependencies();
super._firstBuild();
}
@override
void performRebuild() {
if (_didChangeDependencies) {
state.didChangeDependencies();
_didChangeDependencies = false;
}
super.performRebuild();
}
@override
void update(StatefulWidget newWidget) {
super.update(newWidget);
final StatefulWidget oldWidget = state._widget!;
_dirty = true;
state._widget = widget as StatefulWidget;
try {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic;
} finally {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
}
rebuild();
}
@override
void activate() {
super.activate();
state.activate();
markNeedsBuild();
}
@override
void deactivate() {
state.deactivate();
super.deactivate();
}
@override
void unmount() {
super.unmount();
state.dispose();
state._element = null;
_state = null;
}
bool _didChangeDependencies = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_didChangeDependencies = true;
}
}
ComponentElement实现如下:
abstract class ComponentElement extends Element {
ComponentElement(Widget widget) : super(widget);
Element? _child;
bool _debugDoingBuild = false;
@override
bool get debugDoingBuild => _debugDoingBuild;
@override
void mount(Element? parent, Object? newSlot) {
super.mount(parent, newSlot);
_firstBuild();
}
void _firstBuild() {
rebuild();
}
@override
@pragma('vm:notify-debugger-on-exception')
void performRebuild() {
assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true));
Widget? built;
try {
_debugDoingBuild = true;
built = build();
_debugDoingBuild = false;
debugWidgetBuilderValue(widget, built);
} catch (e, stack) {
_debugDoingBuild = false;
built = ErrorWidget.builder(
_debugReportException(
ErrorDescription('building $this'),
e,
stack,
informationCollector: () => <DiagnosticsNode>[
if (kDebugMode)
DiagnosticsDebugCreator(DebugCreator(this)),
],
),
);
} finally {
_dirty = false;
}
try {
_child = updateChild(_child, built, slot);
assert(_child != null);
} catch (e, stack) {
built = ErrorWidget.builder(
_debugReportException(
ErrorDescription('building $this'),
e,
stack,
informationCollector: () => <DiagnosticsNode>[
if (kDebugMode)
DiagnosticsDebugCreator(DebugCreator(this)),
],
),
);
_child = updateChild(null, built, slot);
}
}
@protected
Widget build();
@override
void visitChildren(ElementVisitor visitor) {
if (_child != null)
visitor(_child!);
}
@override
void forgetChild(Element child) {
assert(child == _child);
_child = null;
super.forgetChild(child);
}
}
Element类核心实现如下:
abstract class Element extends DiagnosticableTree implements BuildContext {
Element(Widget widget)
: assert(widget != null),
_widget = widget;
Element? _parent;
DebugReassembleConfig? _debugReassembleConfig;
_NotificationNode? _notificationTree;
@nonVirtual
@override
bool operator ==(Object other) => identical(this, other);
Object? get slot => _slot;
Object? _slot;
int get depth {
return _depth;
}
late int _depth;
static int _sort(Element a, Element b) {
if (a.depth < b.depth)
return -1;
if (b.depth < a.depth)
return 1;
if (b.dirty && !a.dirty)
return -1;
if (a.dirty && !b.dirty)
return 1;
return 0;
}
@override
Widget get widget => _widget!;
Widget? _widget;
@override
BuildOwner? get owner => _owner;
BuildOwner? _owner;
@mustCallSuper
@protected
void reassemble() {
if (_debugShouldReassemble(_debugReassembleConfig, _widget)) {
markNeedsBuild();
_debugReassembleConfig = null;
}
visitChildren((Element child) {
child._debugReassembleConfig = _debugReassembleConfig;
child.reassemble();
});
_debugReassembleConfig = null;
}
RenderObject? get renderObject {
RenderObject? result;
void visit(Element element) {
if (element._lifecycleState == _ElementLifecycle.defunct) {
return;
} else if (element is RenderObjectElement) {
result = element.renderObject;
} else {
element.visitChildren(visit);
}
}
visit(this);
return result;
}
_ElementLifecycle _lifecycleState = _ElementLifecycle.initial;
void visitChildren(ElementVisitor visitor) { }
@override
void visitChildElements(ElementVisitor visitor) {
visitChildren(visitor);
}
@protected
@pragma('vm:prefer-inline')
Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
if (newWidget == null) {
if (child != null)
deactivateChild(child);
return null;
}
final Element newChild;
if (child != null) {
bool hasSameSuperclass = true;
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);
newChild = child;
} else {
deactivateChild(child);
newChild = inflateWidget(newWidget, newSlot);
}
} else {
newChild = inflateWidget(newWidget, newSlot);
}
return newChild;
}
@mustCallSuper
void mount(Element? parent, Object? newSlot) {
_parent = parent;
_slot = newSlot;
_lifecycleState = _ElementLifecycle.active;
_depth = _parent != null ? _parent!.depth + 1 : 1;
if (parent != null) {
_owner = parent.owner;
}
final Key? key = widget.key;
if (key is GlobalKey) {
owner!._registerGlobalKey(key, this);
}
_updateInheritance();
attachNotificationTree();
}
@mustCallSuper
void update(covariant Widget newWidget) {
_widget = newWidget;
}
@protected
void updateSlotForChild(Element child, Object? newSlot) {
void visit(Element element) {
element._updateSlot(newSlot);
if (element is! RenderObjectElement)
element.visitChildren(visit);
}
visit(child);
}
void _updateSlot(Object? newSlot) {
_slot = newSlot;
}
void _updateDepth(int parentDepth) {
final int expectedDepth = parentDepth + 1;
if (_depth < expectedDepth) {
_depth = expectedDepth;
visitChildren((Element child) {
child._updateDepth(expectedDepth);
});
}
}
void detachRenderObject() {
visitChildren((Element child) {
child.detachRenderObject();
});
_slot = null;
}
void attachRenderObject(Object? newSlot) {
visitChildren((Element child) {
child.attachRenderObject(newSlot);
});
_slot = newSlot;
}
Element? _retakeInactiveElement(GlobalKey key, Widget newWidget) {
final Element? element = key._currentElement;
if (element == null)
return null;
if (!Widget.canUpdate(element.widget, newWidget))
return null;
final Element? parent = element._parent;
if (parent != null) {
parent.forgetChild(element);
parent.deactivateChild(element);
}
owner!._inactiveElements.remove(element);
return element;
}
@protected
@pragma('vm:prefer-inline')
Element inflateWidget(Widget newWidget, Object? newSlot) {
try {
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!;
}
}
final Element newChild = newWidget.createElement();
newChild.mount(this, newSlot);
return newChild;
} finally {
if (isTimelineTracked)
Timeline.finishSync();
}
}
@protected
void deactivateChild(Element child) {
child._parent = null;
child.detachRenderObject();
owner!._inactiveElements.add(child);
}
@protected
@mustCallSuper
void forgetChild(Element child) {
}
void _activateWithParent(Element parent, Object? newSlot) {
_parent = parent;
_updateDepth(_parent!.depth);
_activateRecursively(this);
attachRenderObject(newSlot);
}
static void _activateRecursively(Element element) {
element.activate();
element.visitChildren(_activateRecursively);
}
@mustCallSuper
void activate() {
final bool hadDependencies = (_dependencies != null && _dependencies!.isNotEmpty) || _hadUnsatisfiedDependencies;
_lifecycleState = _ElementLifecycle.active;
_dependencies?.clear();
_hadUnsatisfiedDependencies = false;
_updateInheritance();
attachNotificationTree();
if (_dirty)
owner!.scheduleBuildFor(this);
if (hadDependencies)
didChangeDependencies();
}
@mustCallSuper
void deactivate() {
if (_dependencies != null && _dependencies!.isNotEmpty) {
for (final InheritedElement dependency in _dependencies!)
dependency._dependents.remove(this);
}
_inheritedWidgets = null;
_lifecycleState = _ElementLifecycle.inactive;
}
@mustCallSuper
void debugDeactivated() {
}
@mustCallSuper
void unmount() {
final Key? key = _widget?.key;
if (key is GlobalKey) {
owner!._unregisterGlobalKey(key, this);
}
_widget = null;
_dependencies = null;
_lifecycleState = _ElementLifecycle.defunct;
}
@override
RenderObject? findRenderObject() {
return renderObject;
}
@override
Size? get size {
final RenderObject? renderObject = findRenderObject();
if (renderObject is RenderBox)
return renderObject.size;
return null;
}
Map<Type, InheritedElement>? _inheritedWidgets;
Set<InheritedElement>? _dependencies;
bool _hadUnsatisfiedDependencies = false;
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
_dependencies ??= HashSet<InheritedElement>();
_dependencies!.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget as InheritedWidget;
}
@override
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) {
final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
if (ancestor != null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
@override
InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
return ancestor;
}
@protected
void attachNotificationTree() {
_notificationTree = _parent?._notificationTree;
}
void _updateInheritance() {
_inheritedWidgets = _parent?._inheritedWidgets;
}
@override
T? findAncestorWidgetOfExactType<T extends Widget>() {
Element? ancestor = _parent;
while (ancestor != null && ancestor.widget.runtimeType != T)
ancestor = ancestor._parent;
return ancestor?.widget as T?;
}
@override
T? findAncestorStateOfType<T extends State<StatefulWidget>>() {
Element? ancestor = _parent;
while (ancestor != null) {
if (ancestor is StatefulElement && ancestor.state is T)
break;
ancestor = ancestor._parent;
}
final StatefulElement? statefulAncestor = ancestor as StatefulElement?;
return statefulAncestor?.state as T?;
}
@override
T? findRootAncestorStateOfType<T extends State<StatefulWidget>>() {
Element? ancestor = _parent;
StatefulElement? statefulAncestor;
while (ancestor != null) {
if (ancestor is StatefulElement && ancestor.state is T)
statefulAncestor = ancestor;
ancestor = ancestor._parent;
}
return statefulAncestor?.state as T?;
}
@override
T? findAncestorRenderObjectOfType<T extends RenderObject>() {
Element? ancestor = _parent;
while (ancestor != null) {
if (ancestor is RenderObjectElement && ancestor.renderObject is T)
return ancestor.renderObject as T;
ancestor = ancestor._parent;
}
return null;
}
@override
void visitAncestorElements(bool Function(Element element) visitor) {
Element? ancestor = _parent;
while (ancestor != null && visitor(ancestor))
ancestor = ancestor._parent;
}
@mustCallSuper
void didChangeDependencies() {
markNeedsBuild();
}
@override
void dispatchNotification(Notification notification) {
_notificationTree?.dispatchNotification(notification);
}
bool get dirty => _dirty;
bool _dirty = true;
bool _inDirtyList = false;
bool _debugBuiltOnce = false;
void markNeedsBuild() {
if (_lifecycleState != _ElementLifecycle.active)
return;
if (dirty)
return;
_dirty = true;
owner!.scheduleBuildFor(this);
}
@pragma('vm:prefer-inline')
void rebuild() {
if (_lifecycleState != _ElementLifecycle.active || !_dirty)
return;
performRebuild();
}
@protected
void performRebuild();
}
- State(状态):State是一个存储数据的对象,用于描述Widget的可变状态。当一个Widget需要跟踪一些数据并在运行时进行更改时,可以使用State。State可以与Widget关联,并在需要时更新Widget的显示。
abstract class State<T extends StatefulWidget> with Diagnosticable {
T get widget => _widget!;
T? _widget;
_StateLifecycle _debugLifecycleState = _StateLifecycle.created;
bool _debugTypesAreRight(Widget widget) => widget is T;
BuildContext get context {
return _element!;
}
StatefulElement? _element;
bool get mounted => _element != null;
@protected
@mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
@mustCallSuper
@protected
void didUpdateWidget(covariant T oldWidget) { }
@protected
@mustCallSuper
void reassemble() { }
@protected
void setState(VoidCallback fn) {
assert(fn != null);
final Object? result = fn() as dynamic;
_element!.markNeedsBuild();
}
@protected
@mustCallSuper
void deactivate() { }
@protected
@mustCallSuper
void activate() { }
@protected
@mustCallSuper
void dispose() {
}
@protected
Widget build(BuildContext context);
@protected
@mustCallSuper
void didChangeDependencies() { }
}
以下是一个简单的实例代码,演示了Flutter中递归创建Widget、Element、State和RenderObject的过程:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('递归创建示例'),
),
body: MyWidget(),
),
);
}
}
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'计数器值:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
RaisedButton(
onPressed: _incrementCounter,
child: Text('增加'),
),
if (_counter > 5)
MyWidget() // 递归创建MyWidget
],
),
);
}
}
网友评论