Skip to content

Widget的概念

widget意为”小部件“,在Flutter中widget的地位和作用和原生应用中的控件是一样的。 但是有区别的地方是,Flutter中万物皆widget。

Widget接口

widget是一个不可变的接口,这是为了限制widget中的属性不可变,因为如果属性发现变化就会重新构建widget,就会创建新的widget实例来替换旧的widget实例。因此设置widget是可变的没有任何意义。 在实际使用中我们会间接继承widget接口的子类:StatelessWidgetStatefulWidget来实现新部件。

Flutter中的四棵树

https://juejin.cn/post/7044783155051495438 Widget只负责描述一个UI元素的信息,并不负责UI的布局和绘制。我们知道在原生控件中一个View需要经过测量、布局、绘制才能显示到屏幕上,那么Flutter中是如何实现的呢?

  1. 根据 Widget 树生成一个 Element 树,Element 树中的节点都继承自 Element 类。
  2. 根据 Element 树生成 Render 树(渲染树),渲染树中的节点都继承自RenderObject 类。
  3. 根据渲染树生成 Layer 树,然后上屏显示,Layer 树中的节点都继承自 Layer 类。

StatelessWidget

无状态部件简介

StatelessWidget无状态部件,它继承自Widget,我们需要实现新的控件可以继承StatelessWidget,并会强制重写它的build()方法

groovy
@override
Widget build(BuildContext context) { }

StatelessWidget用于不需要维护状态的场景,它通常在build()方法中通过嵌套其他 widget 来构建UI,在构建过程中会递归的构建其嵌套的 widget 。

Context

build方法中有一个参数是context,它是BuildContext类的一个实例,表示当前widget在widget树中的上下文,每一个widget都会对应一个context对象。(因为每一个widget都是widget树上的一个节点) 通过当前widget的上下文context可以向上遍历widget树查找父级widget的方法

groovy
class ContextRoute extends StatelessWidget  {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Context测试"),
      ),
      body: Container(
        child: Builder(builder: (context) {
          // 在 widget 树中向上查找最近的父级`Scaffold`  widget 
          Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>();
          // 直接返回 AppBar的title, 此处实际上是Text("Context测试")
          return (scaffold.appBar as AppBar).title;
        }),
      ),
    );
  }
}

StatefulWidget

StatelessWidget一样,StatefulWidget也是继承自Widget接口,并重写createElement()方法。 createState() 用于创建和 StatefulWidget 相关的状态,它在StatefulWidget 的生命周期中可能会被多次调用。

State

一个StatefulWidget类会对应一个State类,State表示与其对应的 StatefulWidget 要维护的状态,State 中的保存的状态信息可以:

  • 在 widget 构建时可以被同步读取。
  • 在 widget 生命周期中可以被改变,当State被改变时,可以手动调用其setState()方法通知Flutter 框架状态发生改变,Flutter 框架在收到消息后,会重新调用其build方法重新构建 widget 树,从而达到更新UI的目的。

State中的两个常用属性:

  1. widget:它表示与该 State 实例关联的 widget 实例,由Flutter 框架动态设置。
  2. context:StatefulWidget对应的 BuildContext,widget的上下文。

State的生命周期

State的回调函数:

  1. initState:当widget第一次被插入到widget树时会被调用,对于每一个State对象,Flutter框架只会调用initState一次。通常在改会调用做一些初始化工作。
  2. didChangeDependencies:当State的状态依赖发生变化时会被调用。例如在AWidget中包含了一个BWidget,当BWidget发生了变化,那么AWidget的改回调就会被调用。
  3. build():用于构建widget子树。该方法会在以下场景被调用:
    1. 在调用initState()之后。
    2. 在调用didUpdateWidget()之后
    3. 在调用setState()之后。
    4. 在调用didChangeDependencies()之后。
    5. 在State对象从树中一个位置移除后(会调用deactivate)又重新插入到树的其他位置之后。
  4. reassemble():此回调是专门为了开发调试而提供的,在热重载(hot reload)时会被调用,此回调在Release模式下永远不会被调用。
  5. didUpdateWidget():在 widget 重新构建时,Flutter 框架会调用widget.canUpdate来检测 widget 树中同一位置的新旧节点,然后决定是否需要更新,如果widget.canUpdate返回true则会调用此回调。正如之前所述,widget.canUpdate会在新旧 widget 的 key 和 runtimeType 同时相等时会返回true,也就是说在在新旧 widget 的key和runtimeType同时相等时didUpdateWidget()就会被调用。
  6. deactivate():当 State 对象从树中被移除时,会调用此回调。
  7. dispose():当 State 对象从树中被永久移除时调用;通常在此回调中释放资源。

image.png