第四章:深入理解Widget(三) -- Widget的类型

Flutter-从入门到放弃(目录,持续更新中)

在Flutter中,有三种类型的Widget:Stateless(无状态), Stateful(有状态)Inherited(继承型),所有的Widget都是不可变的,但是有些Widget使用它们的element附加了状态(state)。接下来,我们将分别了解这三种类型的Widget

Stateless widgets

无状态的Widget在它的build()方法被调用后,就无法修改它的状态或者属性了,当属性不需要随时间而更改时,无状态Widget是一个非常好的选择。
在这里插入图片描述
Stateless widgets的生命周期从它的构造器开始,你可以从这里传递参数,然后到build()方法,这是一个需要重写的方法,build()方法决定了Widget的外观。
以下事件会导致 Stateless widgets更新:

  1. 当此widget第一次被加入widget tree时
  2. 依赖状态或继承的widget-祖先节点的状态改变时

Stateful widgets

Stateful widgets 引用有一个State,非常适合在UI中需要动态更新的部分使用。
在这里插入图片描述

Stateful widget将其可变状态存储在一个单独的State类中,这就是为什么每个Stateful widget都必须重写 createState()方法。
每一个Widget的build()方法都有一个BuildContext作为参数,BuildContext可以告诉你你在widget tree的位置,你还可以通过BuildContext访问任何widget的element,稍后,您将看到为什么BuildContext很重要,特别是对于从parent widget 访问状态信息。
在这里插入图片描述
我们仔细看看上图中的生命周期:

1. 当将BuildContext绑定到widget时,一个内部标志mounted将设置为true,这使框架知道这个widget被加入到widget tree上了。

2. initState() 是widget被创建后第一个被调用的方法,类似Android 中的onCreate() 或IOS中的viewDidLoad() 。

3. 当framework开始构建widget时,它会在initState()之后调用didChangeDependencies()
方法,如果widget的state对象所依赖的 inherited widget发生了变化,didChangeDependencies()方法可能被再次调用。后面我们会学习 inherited widget

4. 最终framework会回调build()方法,这个方法对开发者来说是最重要的,因为每次widget需要渲染的时候都会调用该方法。widget tree中的每一个widget都会被遍历回调该方法,因此这个方法里的操作必须是轻量的,不能进行耗时操作,就像你在Andorid的main thread中不能进行耗时操作一样。

5. 当父widget发生变化或者需要重绘时, framework会调用 didUpdateWidget(_) 方法,此时你会得到一个旧的widget对象作为参数,你可以把这个对象与当前widget进行对比并进行处理。

6. 当你想要修改widget中的状态时,调用setState(),然后framework会调用widget的build()方法
注意:在编写异步代码的时候,调用setState()之前需要确保mounted值为true,因为此时widget可能从widget tree中被移除了

7. 当你将widget从widget tree移除时,framework会调用deactivate()方法,在某些情况下,framework会重新将state对象添加进widget tree的其他部分。

8. 当您从widget tree中永久删除widget及其状态时,框架会dispose()方法,这个方法非常重要,因为您需要在其中处理内存清理,例如取消订阅流和处理动画或控制器等。完成dispose()方法的经验法则是检查你在当前状态中定义的任何属性,并确保您已经正确地处理了它们。

创建Stateful Widget

回到我们的Card2中,它是一个Stateless Widget,我们点击头像右边的收藏按钮时,现在只能弹出一个文本提示,而不是像通常情况那样会切换成已收藏的图标,我们现在就来修改一下,实现想要的那种效果。
在这里插入图片描述
我们可以把Card2变成Stateful Widget,然后再把其中的AuthorCard变成Stateful Widget,但是记住Stateful Widget可能会经常进行重绘,重绘可能是自己触发的也有可能是父Widget或兄弟节点重绘时触发的,这些不必要的重绘会拖累我们的效率,我们尽量让重绘发生在最小的范围内
我们回到AuthorCard中,Android Studio 提供了一些快捷方式帮助我们提高效率。右键点击AuthorCard,然后选择 Show Context Actions
在这里插入图片描述
在弹出的菜单中,选择 Convert to StatefulWidget,它会自动修改成Stateful Widget。
在这里插入图片描述

上面进行了两个事情:

  1. 进行了重构把AuthorCard变成了Stateful Widget,并实现了 createState()方法
  2. 创建了 _AuthorCardState类,它是一个state类,保存了widget生命周期中可变的数据

现在我们在AuthorCardState中添加一个变量来记录它是否被收藏了:

bool _isFavorited = false;

现在把AuthorCard中原来的IconButton替换为以下代码:

	IconButton(
            //根据是否收藏来显示不同的图标
            icon: Icon(_isFavorited ? Icons.favorite : Icons.favorite_border),
            iconSize: 30,
            //变成红色更符合常规效果
            color: Colors.red[400],
            onPressed: () {
              //点击时,更新状态
              //setState()方法调用后引起重绘
              setState(() {
                _isFavorited = !_isFavorited;o
              });
            },
          )

实际效果如下,当然不是我自己的截图,我的截图太大了。。
在这里插入图片描述
现在我们来看看element tree是如何来管理状态变化的。
framework在构建widget tree的时候也会为每个widget对象创建一个element对象,在本例中,创建了一个StatefulElement对象来管理state 对象
在这里插入图片描述
当用户点击心形按钮时, setState()方法被调用,将_isFavorited变量设为true,同时state对象将element标记为dirty,这将会触发渲染,调用build()方法。
在这里插入图片描述
element对象将旧的widget移除并用一个新的对象来替换它,而新的对象有一个完整的心形。
在这里插入图片描述
framework总是尽可能的只更新需要改变的widget,尽可能的复用来提高其效率。

Inherited widgets

Inherited widgets可以让你在树结构中,从父element中访问到state 信息。
假设你在widget tree中有一个要访问的数据片段,一种解决方案是将数据作为参数传递到每个嵌套的widget上——但这很烦人,也很可能导致错误。如果有一种中心化的方式来访问这些数据,会不会更好呢?
在这里插入图片描述
这就是Inherited widgets的作用所在!通过在树中添加Inherited widgets,你可以引用来自其任何后代的数据,这被称为状态提升。例如以下场景:

  • 访问Theme对象以更改UI的外观。
  • 调用一个API Service对象来从web中获取数据。
  • 订阅流以根据接收到的数据更新UI

Inherited widgets是一个高级点的课题,我们会在后面的章节里继续深入学习它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值