前言
如何快速高效的掌握一门知识,建议先阅读下这篇文章关于学习的一些看法。
Flutter渲染原理系列文章:
Flutter渲染原理系列之构建Widget树
Flutter渲染原理系列之构建Element树~敬请期待
Flutter渲染原理系列之构建RenderObject树~敬请期待
Flutter渲染原理系列之合成Layer树~敬请期待
Flutter渲染原理系列之GPU渲染~敬请期待
Flutter渲染原理系列之屏幕刷新(Async)~敬请期待
Flutter渲染原理系列之runApp执行流程~敬请期待
一、Widget概念
定义:
Widget是FLutter中定义 和构建 用户界面的基本单元。
补充说明:
Widget不仅可以看着是UI元素,还可以表示功能组件 ,比如用于App主题数据传递的Theme、用于手势检测的GestureDetector等。Widgets通过布局组合 形成一种层次结构关系 。每个Widget都嵌套在其父级的内部,并可以通过父级接收上下文。- 从根布局 (托管
Flutter应用的容器,通常是MaterialApp或CupertinoApp)开始,自上而下都是这样的结构。
特点:
- 不可变性 :每个
Widget都是不可变的 ,其内部属性都是final修饰的,这意味着一旦创建不能改变。 - 描述性 :
Widget描述了给定其当前配置 和状态时,视图应该看起来像什么。 - 组合性 :
Widget可以组合在一起形成更复杂的UI组件。 - 响应式 :当
Widget的状态发生变化时,Flutter框架会重新构建UI。
二、Widget源码说明
dart
/// 1. Describes the configuration for an [Element].
2. @immutable
abstract class Widget extends DiagnosticableTree {
3. final Key? key;
@protected
@factory
4. Element createElement();
5. static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
上述代码中,只保留了核心属性及方法,其他暂不讨论,下面进行详细说明。
1、类功能描述:
Widget的功能是描述 一个UI元素的配置信息。- 换言之,
Widget并不是最终绘制在屏幕上的显示元素。 - 配置信息 :即
Widget接收的参数,如Text,文本的内容 、对齐方式 、文本样式 等都是它的配置信息。
2、@immutable:
- 该注解表示
Widget是不可变的 ,这会限制Widget中的属性必须是不可变的 (final修饰)。 - 不可变的原因 : 在
Flutter中, 如果属性变化就会重建Widget树,即新实例会替换旧的实例,所以允许其属性变化是无意义的。这也是其属性必须是final的原因。
3、Key:
Widget的唯一标识。- 主要用于
build时判断两个Widget是否可以更新,在canUpdate()方法中使用。
4、createElement():
Widget是抽象类,该方法是其核心方法,使用@protected @factory两注解修饰,意味着子类必须重写该方法。- 创建一个与
Widget关联的Element。 Element是Widget的运行时表示,可管理Widget在树中的位置 ,同时负责创建 和更新RenderObject。- 一个
widget可对应多个Element,原因是一个特定的Widget实例可以被复用,并出现在Widget树的不同位置,因此可以有多个对应的Element。
5、canUpdate(...):
- 用于判断两个
Widget是否可以更新。 - 如果两个
Widget的类型和Key相同,则认为可以更新。 - 该方法用于
Widget树的比较 和更新过程。
三、StatelessWidget
scala
abstract class StatelessWidget extends Widget {
const StatelessWidget({ super.key });
/// Creates a [StatelessElement] to manage this widget's location in the tree.
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
- 无状态 的
Widget。 createElement():- 重写了父
widget中的方法。返回一个StatelessElement对象,该对象间接继承自Element类,与StatelessWidget相对应。 StatelessElement负责管理Widget在树中的位置 ,同时负责创建 和更新RenderObject。
- 重写了父
build(BuildContext context):- 子类必须实现该方法。
- 它接受一个
BuildContext参数,并返回一个Widget。 - 用于构建
UI,返回的Widget描述了UI的当前状态。
StatelessWidget是用于构建无状态的UI的基类 ,它通常在build方法中通过嵌套 其他Widget来构建UI,在构建过程中会递归 的构建其嵌套的Widget。
四、StatefulWidget
scala
abstract class StatefulWidget extends Widget {
const StatefulWidget({ super.key });
/// Creates a [StatefulElement] to manage this widget's location in the tree.
@override
StatefulElement createElement() => StatefulElement(this);
@protected
@factory
State createState();
}
- 有状态 的
Widget。 createElement():- 重写了父
widget中的方法。返回一个StatefulElement对象,该对象间接继承自Element类,与StatefulWidget相对应。 StatefulElement负责管理Widget在树中的位置 ,同时负责创建 和更新RenderObject。
- 重写了父
createState():- 子类必须实现 该方法,该方法返回一个
State对象。 - 用于创建和
StatefulWidget相关的状态(State),具有一一对应的关系。 - 它在
StatefulWidget的生命周期中可能被多次调用。
- 子类必须实现 该方法,该方法返回一个
StatefulWidget用于构建具有状态 的UI的基类 。它通过createState方法返回一个State对象来管理状态。通过State对象的setState方法来通知框架状态发生变化,并触发UI的重新构建。
五、Widget树是如何构建的?
1、准备Widget树:
- 应用程序的
UI是由一个或多个Widget组成的树形结构。 - 每个
Widget都可以包含子Widget,形成一个层次结构。
2、构建Widget树:
- 当
Widget树准备好后,Flutter引擎会调用build方法来构建Widget树。 - 每个
Widget的build方法返回一个Widget,这个Widget描述了UI的当前状态。
此阶段对应第一节中渲染原理 图中的build阶段。
六、总结
理解Widget相关概念及其源码对于深入了解Flutter的UI构建机制非常重要。希望这些信息能帮助你更好地理解Widget的工作原理。
码字不易,记得关注 + 点赞 + 收藏