Flutter学习-30-Flutter的key

「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」。

  • 我们在快捷方式创建stateless Widget或者stateful Widget时候会让我们创建一个key,之前一直没有讲讲解,接下来 就探讨下。

1. 例子

我们创建一个listView添加3个cell,同时给他随机颜色,点击的时候移除第一个元素,

class _keyDemoState extends State<keyDemo>{
  List<String> names = ['1111','2222','3333'];

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        appBar: AppBar(),
        body: ListView(
          children: names.map((str) {
            return listCell(name: str,);
          }).toList(),

        ),
    floatingActionButton: FloatingActionButton(
    onPressed: (){

       names.removeAt(0);
       setState(() {

       });
    },
    tooltip: 'delete',
    child: const Icon(Icons.delete),
      ),
    )
    );
  }
}
复制代码

cell的样式

class listCell extends StatelessWidget {
  final String? name;
  final Color bgcolor = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1) ;
   listCell({Key? key,this.name,}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
        height: 44,
        child: ListTile(

          tileColor:bgcolor ,


          title: Text(name!),
        )
    );
  }
}
复制代码

image.png

我们点击删除,移除了第一个元素,但是setState后重新build了,颜色重新随机了

image.png

这显然不是我们想要的样子。我们把cell换成statefulWidget

image.png 点击删除

image.png

发现数据发生了变化,但是颜色没有发生变化,我们删除了最后一个的颜色和第一个的文字。

  • 这是因为在删除第一条数据的时候,Widget对应的Element并没有改变;
  • Element中对应的State引用也没有发生改变;
  • 在更新Widget的时候,Widget使用了没有改变的Element中的State

2. key的使用

我们给我们的statefulWidget添加key

image.png

点击删除后,得到我们想要的效果

image.png

我们查看源码

image.png

当我们的 [runtimeType] and [key]没有发生变化的时候Element就不更新,我们删除第一个widget的时候,因为widgetkey都是空而且[runtimeType]也是一样的,所以直接使用之前的Element

image.png

我们使用随机key的话

image.png

删除后

image.png

也验证了每次我们的key发生变化后,Element会强制刷新,那么对应的State也会重新创建

3. key的分类

key是一个抽象类,里面有个工厂构造函数可以返回key

image.png key有2个子类LocalKeyGlobalKey

3.1 LocalKey

LocalKey主要分为3个子类

  • ValueKey

    • ValueKey是当我们以特定的值作为key时使用,比如一个字符串、数字等等
  • ObjectKey

    • 如果两个模型,他们的类型一样,使用type作为他们的key就不合适了
    • 我们可以创建出一个模型对象,使用对象来作为key
  • UniqueKey

    • 如果我们要确保key的唯一性,可以使用UniqueKey;
    • 比如我们之前使用随机数来保证key的不同,这里我们就可以换成UniqueKey;

3.2 GlobalKey

可以帮助我们访问某个Widget的信息,包括WidgetStateElement等对象

class GlobalKeyDemo extends StatelessWidget {
  final GlobalKey<_ChildPageState> _globalKey = GlobalKey();

  GlobalKeyDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('GlobalKeyDemo'),
      ),
      body: ChildPage(
        key: _globalKey,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _globalKey.currentState!.setState(() {
            _globalKey.currentState!.data =
                'old:' + _globalKey.currentState!.count.toString();
            _globalKey.currentState!.count++;
          });
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

class ChildPage extends StatefulWidget {
  const ChildPage({Key? key}) : super(key: key);

  @override
  _ChildPageState createState() => _ChildPageState();
}

class _ChildPageState extends State<ChildPage> {
  int count = 0;
  String data = 'hello';
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          Text(count.toString()),
          Text(data),
        ],
      ),
    );
  }
}
复制代码

image.png

猜你喜欢

转载自juejin.im/post/7035930570056007716