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

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

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

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

Stateless widgets

无状态的Widget在它的build()方法被调用后,就无法修改它的状态或者属性了,当属性不需要随时间而更改时,无状态Widget是一个非常好的选择。

Stateless widgets的生命周期从它的构造器开始,你可以从这里传递参数,然后到build()方法,这是一个需要重写的方法,build()方法决定了Widget的外观。
以下事件会导致 Stateless widgets更新:

当此widget第一次被加入widget tree时依赖状态或继承的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,我们点击头像右边的收藏按钮时,现在只能d出一个文本提示,而不是像通常情况那样会切换成已收藏的图标,我们现在就来修改一下,实现想要的那种效果。

我们可以把Card2变成Stateful Widget,然后再把其中的AuthorCard变成Stateful Widget,但是记住Stateful Widget可能会经常进行重绘,重绘可能是自己触发的也有可能是父Widget或兄弟节点重绘时触发的,这些不必要的重绘会拖累我们的效率,我们尽量让重绘发生在最小的范围内。
我们回到AuthorCard中,Android Studio 提供了一些快捷方式帮助我们提高效率。右键点击AuthorCard,然后选择 Show Context Actions

在d出的菜单中,选择 Convert to StatefulWidget,它会自动修改成Stateful Widget。

上面进行了两个事情:

进行了重构把AuthorCard变成了Stateful Widget,并实现了 createState()方法创建了 _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是一个高级点的课题,我们会在后面的章节里继续深入学习它。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/993147.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存