深色模式
Widget 源码分析
Widget分类
Widget
的继承关系如图:
Widget
可以分为3类:
构建类
Widget
StatelessWidget
、StatefulWidget
以及它们的子类。作用是构建页面,业务开发主要是使用这一类Widget,构建的逻辑在
StatelessWidget
、State
的build()
方法中。代理类
Widget
ProxyWidget
及其子类。为子元素提供附加信息。
渲染类
Widget
RenderObjectWidget
及其子类。参与渲染的。
核心源码分析
Widget
key
dart
final Key? key;
在同一父节点下,用作兄弟节点间的唯一标识,主要用于控制当 Widget
更新时,对应的 Element
如何处理 (是更新还是新建)。若某 Widget
是其父元素唯一的子节点时,一般不用设置 key
。
createElement()
dart
Element createElement();
抽象方法
canUpdate()
dart
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
这是一个静态方法,用于判断是否可以更新Element
,而不是创建新的Element
。
StatelessWidget
createElement()
dart
@override
StatelessElement createElement() => StatelessElement(this);
StatelessWidget
对应的Element
是StatelessElement
。
build()
抽象方法:
dart
Widget build(BuildContext context);
StatefulWidget
createElement()
dart
@override
StatefulElement createElement() => StatefulElement(this);
StatefulWidget
对应的 Element
是 StatefulElement
。
createState()
与StatelessWidget
相比,没有 build()
方法,它有一个createState()
方法,build()
由State类完成。
dart
State createState();
State
ProxyWidget
dart
abstract class ProxyWidget extends Widget {
const ProxyWidget({super.key, required this.child});
final Widget child;
}
源码很简单,它作为一个基类存在,目的是为child
提供一些附加信息。
ParentDataWidget
createElement()
dart
@override
ParentDataElement<T> createElement() => ParentDataElement<T>(this);
applyParentData()
dart
@protected
void applyParentData(RenderObject renderObject);
InheritedWidget
介绍
用于高效地向下传播信息的 widget 的基类。
要从构建上下文中获取特定类型的继承 widget 的最近实例,请使用 [BuildContext.dependOnInheritedWidgetOfExactType]。
当以这种方式引用继承 widget 时,当继承 widget 本身改变状态时,将导致使用者重新构建。
以下是一个名为 FrogColor
的继承 widget 的框架:
dart
class FrogColor extends InheritedWidget {
const FrogColor({
super.key,
required this.color,
required super.child,
});
final Color color;
static FrogColor? maybeOf(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<FrogColor>();
}
static FrogColor of(BuildContext context) {
final FrogColor? result = maybeOf(context);
assert(result != null, 'No FrogColor found in context');
return result!;
}
@override
bool updateShouldNotify(FrogColor oldWidget) => color != oldWidget.color;
}
实现 of
和 maybeOf
方法
惯例是在 [InheritedWidget] 上提供两个静态方法,of
和 maybeOf
,它们调用 [BuildContext.dependOnInheritedWidgetOfExactType]。这允许类在范围内没有 widget 的情况下定义自己的回退逻辑。
of
方法通常返回非空实例,并在找不到 [InheritedWidget] 时断言,而 maybeOf
方法返回可空实例,在找不到 [InheritedWidget] 时返回 null。of
方法通常通过内部调用 maybeOf
来实现。
有时,of
和 maybeOf
方法返回一些数据而不是继承 widget 本身;例如,在这种情况下,它可以返回 [Color] 而不是 FrogColor
widget。
偶尔,继承 widget 是另一个类的实现细节,因此是私有的。在这种情况下,of
和 maybeOf
方法通常在公共类上实现。例如,[Theme] 被实现为一个构建私有继承 widget 的 [StatelessWidget];[Theme.of] 使用 [BuildContext.dependOnInheritedWidgetOfExactType] 查找该私有继承 widget,然后返回其中的 [ThemeData]。
调用 of
或 maybeOf
方法
使用 of
或 maybeOf
方法时,context
必须是 [InheritedWidget] 的后代,意味着它必须在树中位于 [InheritedWidget] "下方"。
在这个例子中,使用的 context
来自 [Builder],它是 FrogColor
widget 的子项,所以这样可以工作:
dart
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: FrogColor(
color: Colors.green,
child: Builder(
builder: (BuildContext innerContext) {
return Text(
'Hello Frog',
style: TextStyle(color: FrogColor.of(innerContext).color),
);
},
),
),
);
}
}
在这个例子中,使用的 context
来自 MyOtherPage
widget,它是 FrogColor
widget 的父项,所以这不能工作,并且在调用 FrogColor.of
时会断言:
dart
class MyOtherPage extends StatelessWidget {
const MyOtherPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: FrogColor(
color: Colors.green,
child: Text(
'Hello Frog',
style: TextStyle(color: FrogColor.of(context).color),
),
),
);
}
}
另请参见:
- [StatefulWidget] 和 [State],用于在其生命周期内可以多次不同构建的 widget。
- [StatelessWidget],用于在给定特定配置和环境状态时始终以相同方式构建的 widget。
- [Widget],用于概述 widget 的一般信息。
- [InheritedNotifier],一个值可以是 [Listenable] 的继承 widget,每当值发送通知时都会通知依赖者。
- [InheritedModel],一个允许客户端订阅值的子部分更改的继承 widget。