Flutter中Key的原理及使用 LocalKey (一)


发文时间:2022年03月22日 14:53:13     编辑:Aaron      标签:flutter key 1639


简述关于flutter中的Key和案例 - LocalKey。LocalKey下有3个子类 1:ValueKey、 2:ObjectKey、 3:UniqueKey、

前言

  在Flutter 中一切皆 Widget,同一级中相同类型的Widget不给它传Key的话,Flutter有时候就会出现分不清它们之间的对应关系,尤其是Widget之间的顺序发生改变的时候,此时 我们就需要传个key给它 而 Widget 的构造方法中有个可选参数 Key。

Key的种类

   在Flutter中key有两个子类分别为

     1、 LocalKey 依官方的解释为局部键,在同一级的Widget中要唯一,可以理解为同级中的唯一级。

        而LocalKey又有3个子类     

            1.1:ValueKey

            1.2:ObjectKey

            1.3:UniqueKey 

     2、GlobalKey 全局键,就是在整个APP中必须是唯一的。

关于LocalKey中的三个子类详解

  1: ValueKey -案例 

   ValueKey源码

/// Creates a key that delegates its [operator==] to the given value.
const ValueKey(this.value);

/// The value to which this key delegates its [operator==]
final T value;

@override
bool operator ==(Object other) {
  if (other.runtimeType != runtimeType)
    return false;
  return other is ValueKey      && other.value == value;
}

案例:假设在Column中存在三个不同颜色的TestBox按钮块,TestBox代码如下,内包含背景色和count以此来记录值。

class TestBox extends StatefulWidget {
  final Color color;
  TestBox(this.color, {Key key}) : super(key: key);
  @override
  _BoxState createState() => _BoxState();
}

class _BoxState extends State {
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return Container(
        width: 150,
        height: 150,
        color: widget.color,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('$count', style: TextStyle(color: Colors.white)),
            IconButton(
              onPressed: () {
                setState(() {
                  count++;
                });
              },
              icon: Icon(Icons.add),
            )
          ],
        ));
  }
}

如下图所示 案例中分别有红黄蓝 且对应的数字分别为 红=1, 黄=2,蓝=3

image.png

假设把红色1的Widget注释掉,然后hotreload一下,此时的ui会是怎样呢?

image.png

    效果如下,如图所示 红色块确实已经消失了,按常理来说此时红色的确实要去掉 黄2和蓝3应该留下,但是此时的方块值已经发生了改变 由 红=1, 黄=2,蓝=3 改变为:黄=1,蓝=2,由此可以看出flutter已经分辨不出来谁是谁了,或者说颜色并不能当做是widget的唯一标识。

image.png

    那么就需要类似于uuid来区分每一个widget的,这就是key的作用了,如果我们给每一个widget传入不同的key,就相当于每一个widget有各自的id标识,那么flutter就不会混淆它们的值了。

image.png

image.png

     在同一级下的widget 因为有了key(ValueKey),flutter就可以区分,所以我们现在无论是删除还是调换widget的顺序他都可以按key对号入座对应的参数,而不会混淆。

     提问: 在什么业务场景下可能会用到这个ValueKey呢 ?

     答:假设在类似于购物车列表的场景下,每个商品明细都不一致,而你想对每个商品进行滑动排序或者删除操作,使用ValueKey将是不错的选择。

  2: ObjectKey -案例 

通过查看源码可得知 ObieckKey和ValueKey大同小区,主要的区别是value的类型从T变成了为Object,operator方法也不一样,identical对比是否是相等或者说相同的时候,它其实属于对比引用或者说指针是否相等即可。

/// Creates a key that uses [identical] on [value] for its [operator==].
const ObjectKey(this.value);

/// The object whose identity is used by this key's [operator==].
final Object? value;

@override
bool operator ==(Object other) {
  if (other.runtimeType != runtimeType)
    return false;
  return other is ObjectKey
      && identical(other.value, value);
}

@override
int get hashCode => hashValues(runtimeType, identityHashCode(value));

案例:建立一个稍微复杂的类以此查看二者的区别:

class People{
  final String name;
  final int age;
  People(this.name, this.age);
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is People && runtimeType == other.runtimeType && name 
          == other.name && age == other.age;
  @override
  int get hashCode => name.hashCode ^ age.hashCode;
}

    测试 ValueKey的operator方法,当年龄相等并且姓名相等时,就判断是相等的,那么程序会是怎样

此时代码如果是这样的话:

image.png

    果不其然,程序报错了,我们换成ObjectKey试试:

image.png

OK~ 完美运行

这就是因为People('Aaron', 18)是new出来的新对象(小提示:在Dart中,new关键字是可以被忽略的)  flutter判断两者不是同一个对象,因为对应的ObjeckKey也不相等,这就是ObjectKey和ValueKey的主要区别。

  3: UniqueKey -案例     

UniqueKey源码

class UniqueKey extends LocalKey {
  /// Creates a key that is equal only to itself.
  ///
  /// The key cannot be created with a const constructor because that implies
  /// that all instantiated keys would be the same instance and therefore not
  /// be unique.
  /// ignore: prefer_const_constructors_in_immutables , 
  ///never use const for this class
  UniqueKey();

  @override
  String toString() => '[#${shortHash(this)}]';
}

    顾名思义,UniqueKey在flutter中是一个独一无二的Key,也就是说它只和自己相等,如若在build内定义 每次hotReload后就会丢失状态,因为新的Uniquekey和旧的是不一致的,所以就状态就无法保留,因此UniqueKey()和UniqueKey()是不相等的。期初学习到这个UniqueKey后,时常在想到底在什么场景下才用这个呢,自以为的感觉有些鸡肋...  但经过查阅后发现并不是(暴露了水平

    其实在flutter中丢失状态也是一种它的用法,一般可以在动画中使用到,另外UniqueKey不用传入value,当你不想传value但是又想让它丢失状态时就挺方便的,我个人是比较头疼起名的.. 时常和同事讲起 编程最难的不是代码而是如何起名

    关于上述所提到的每次hotReload后UniqueKey()会丢失状态,假设我们又不想让它每次都会丢失状态的话,可以把UniqueKey定义到build的外部就好了,

final AaronKey1 = UniqueKey();
final AaronKey2 = UniqueKey();

    因为程序一开始就new出来的两个Key,所以在使用的时候,key是没有改变的,也就达到了想要的效果。


                    

                                                                                                          知足常乐~

 

若无特殊说明,此文章为博主原创。
写稿不易,如需转载,请注明出处: https://www.aaroner.cn/art/24.html




SITE MAP

  FOLLOW US