title: “Flutter中的Key(二)”
comments: true
share: true
toc: true
categories:
- Flutter
tags:
Flutter中的Key(二)
本文继续分析flutter中各种各样的key
key的种类
1 |
|
默认的key会通过工厂方法传入的key 创建一个ValueKey,Key派生出两种用途不同的的key:LocalKey和GlobalKey,类图如下
GlobalKey
- GlobalKey唯一标识Elements,它提供了与Element相关联的访问,如BuildContext、State(对于StatefulWidget)
- 不要在两个Widget中使用相同的GlobalKey
- Global keys 是很昂贵的,如果你不需要访问BuildContext、Element、State这些的话,请尽量使用[Key], [ValueKey], [ObjectKey] 或者 [UniqueKey]
1 | abstract class GlobalKey<T extends State<StatefulWidget>> extends Key { |
GlobalKey 使用了一个静态常量 Map 来保存它对应的 Element。你可以通过 GlobalKey 找到持有该GlobalKey的 Widget,State 和 Element。它们允许widget在应用中的任何位置更改父级而不会丢失State,内部有几个属性,意味着你可以访问到currentContext、currentContext和currentState(如果是StatefullWidget),这是通过过在Element被mount到树上的时候调用_register,如果是类型是GlobalKey,那么Element就会加入到一个静态Map里,unmount的时候调用_unregister被移除
- 比如在不同的屏幕上使用相同的Widget,但是保持相同的State,则需要使用GlobalKeys
1 | class SwitcherScreenState extends State<SwitcherScreen> { |
但是我们想要在外部改变该状态,这时候就需要使用 GlobalKey
1 | class _ScreenState extends State<Screen> { |
通常,GlobalKey看起来有点像全局变量。也有其他更好的办法去查找状态,比如 InheritedWidget、Redux 或 Block Pattern。
Localkey
LocalKey 直接继承至 Key,它应用于拥有相同父 Element 的小部件进行比较的情况,也就是上述例子中,有一个多子 Widget 中需要对它的子 widget 进行移动处理,这时候你应该使用Localkey。
Localkey 派生出了许多子类 key:
- ValueKey : ValueKey(‘String’)
- ObjectKey : ObjectKey(Object)
- UniqueKey : UniqueKey()
Valuekey 又派生出了 PageStorageKey : PageStorageKey(‘value‘)
- ValueKey
1 | class ValueKey<T> extends LocalKey { |
派生自LocalKey,接受一个泛型类,重写了==方法和hash方法,需要同时校验runtimeType和value
使用场景
如果您有一个 Todo List 应用程序,它将会记录你需要完成的事情。我们假设每个 Todo 事情都各不相同,而你想要对每个 Todo 进行滑动删除操作。
这时候就需要使用 **ValueKey。
- PageStoreKey
1 | class PageStorageKey<T> extends ValueKey<T> { |
PageStorageKey是继承自ValueKey,传入一个value,它是用于保存Scrollable的偏移
Scrollable(实际是ScrollPositions)使用PageStorage保存它们的滚动偏移,每次滚动完成时,存储的滚动信息都会更新。
PageStorage用于保存和恢复比widget生命周期更长的值,这些值存储在per-route Map中,它的key由widget及它的祖先的PageStorageKeys定义
使用场景
当你有一个滑动列表,你通过某一个 Item 跳转到了一个新的页面,当你返回之前的列表页面时,你发现滑动的距离回到了顶部。这时候,给 Sliver 一个 PageStorageKey 它将能够保持 Sliver 的滚动状态
- ObjectKey
1 | class ObjectKey extends LocalKey { |
ObjectKey也是集成自LocalKey,而且构造方法也是需要传入一个value,但是这个value是Object类型的,也就是说可以传任意类型,identical 方法返回的是两个Object的hashCode是否相等,当runtimeType跟value.hashCode都相等的情况下,ObjectKey才会被认为相等,它跟ValueKey的区别在于它比较的是value的引用,而ValueKey是直接比较值
使用场景
如果你有一个生日应用,它可以记录某个人的生日,并用列表显示出来,同样的还是需要有一个滑动删除操作。
我们知道人名可能会重复,这时候你无法保证给 Key 的值每次都会不同。但是,当人名和生日组合起来的 Object 将具有唯一性。
这时候你需要使用 ObjectKey!
- UniqueKey
1 | /// A key that is only equal to itself. |
如果组合的 Object 都无法满足唯一性的时候,你想要确保每一个 Key 都具有唯一性。那么,你可以使用 UniqueKey。它将会通过该对象生成一个具有唯一性的 hash 码。
不过这样做,每次 Widget 被构建时都会去重新生成一个新的 UniqueKey,失去了一致性