1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @immutable abstract class Widget extends DiagnosticableTree { const Widget({ this.key });
final Key? key;
@protected @factory Element createElement();
@override String toStringShort() { final String type = objectRuntimeType(this, 'Widget'); return key == null ? type : '$type-$key'; }
@override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense; }
@override @nonVirtual bool operator ==(Object other) => super == other;
@override @nonVirtual int get hashCode => super.hashCode;
static bool canUpdate(Widget oldWidget, Widget newWidget) { return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key; }
}
|
Widget的特点:
- 声明式UI,描述UI的层级结构、样式、布局过程
- Widget都是不可变的,对于变化的部分通过Stateful Widget-State的方式实现,也就是我们开发中使用的StatefulWidget,操作逻辑在State中
开发过程中,我们会使用StatelessWidget
和StatefulWidget
,这两个类都继承自Widget
。而整个过程就是将Widget树转换成Element树,再转换成RenderObject树,最终通过底层skia绘制。
如果我们绘制的UI也是不可变的,那么我们可以使用StatelessWidget
,这样在创建的时候绘制一次即可。如果UI需要根据状态发生变化,那么我们可以使用StatefulWidget
。对于StatefulWidget
,我们需要实现State
类,这个类持有Widget
和Element
,用来管理Widget
的状态。
Widget大致可以分为3类:
- Component Widget,组合类Widget,通过组合单一的Widget可以获得复杂的Widget
- Proxy Widget,代理类Widget,本身不涉及Widget内部逻辑,只是为Child Widget提供一些附加的中间功能。比如InheritedWidget用于传递共享信息、ParentDataWidget用于配置布局信息
- RenderObjectWidget,渲染类Widget,参与Layout、Paint流程,其有对应的RenderObject
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class FooWidget extends StatelessWidget { const FooWidget({super.key});
@override Widget build(BuildContext context) { return const Placeholder(); } }
|
1 2 3 4 5 6 7 8 9 10
| abstract class StatefulWidget extends Widget { const StatefulWidget({ Key key }) : super(key: key); @override StatefulElement createElement() => StatefulElement(this); @protected State createState(); }
|
State
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| 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() { }
@mustCallSuper @protected void didUpdateWidget(covariant T oldWidget) { }
@protected @mustCallSuper void reassemble() { }
@protected void setState(VoidCallback fn) { final Object? result = fn() as dynamic; _element!.markNeedsBuild(); }
@protected @mustCallSuper void deactivate() { } @protected @mustCallSuper void activate() { }
@protected @mustCallSuper void dispose() { if (kFlutterMemoryAllocationsEnabled) { MemoryAllocations.instance.dispatchObjectDisposed(object: this); } }
@protected Widget build(BuildContext context);
@protected @mustCallSuper void didChangeDependencies() { }
}
|
ParentDataWidget作为 Proxy 型 Widget,其功能主要是为其他 Widget 提供ParentData信息。虽然其 child widget 不一定是 RenderObejctWidget 类型,但其提供的ParentData信息最终都会落地到 RenderObejctWidget 类型子孙 Widget 上。
比如Positioned
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Positioned extends ParentDataWidget<StackParentData> {
@override void applyParentData(RenderObject renderObject) { assert(renderObject.parentData is StackParentData); final StackParentData parentData = renderObject.parentData! as StackParentData; bool needsLayout = false;
if (parentData.left != left) { parentData.left = left; needsLayout = true; }
if (parentData.top != top) { parentData.top = top; needsLayout = true; } ... if (needsLayout) { final RenderObject? targetParent = renderObject.parent; if (targetParent is RenderObject) { targetParent.markNeedsLayout(); } } } }
|
参考InheritedWidget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| abstract class RenderObjectWidget extends Widget { const RenderObjectWidget({ super.key });
@override @factory RenderObjectElement createElement();
@protected @factory RenderObject createRenderObject(BuildContext context);
@protected void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }
@protected void didUnmountRenderObject(covariant RenderObject renderObject) { } }
|
RenderObjectWidget的几个子类:LeafRenderObjectWidget、SingleChildRenderObjectWidget、MultiChildRenderObjectWidget只是重写了createElement方法以便返回各自对应的具体的 Element 类实例。
参考