一个例子直观的告诉你flutter中key的作用

笔者之前是java后端开发,转flutter之后又被公司裁员,当时对flutter知之甚少,去面试没看面经遂被第一题考倒:flutter中widget的key有什么作用?

查阅了网上很多描述都不太理解,最近在某视频学习网站看了一个讲解视频才略有了解。

没有key的情况下

先上代码,以下代码自定义了组件Box,Box中用GestureDetector包裹了一个有定义颜色的Container,每点击Box一次就会使的里面的数字+1.

js 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: MyHome(),
    ),
  );
}

class MyHome extends StatefulWidget {
  const MyHome({super.key});

  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: [
            Box(Colors.red),
            Box(Colors.yellow),
            Box(Colors.blue),
          ],
        ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  const Box(this.color); // 接收并传递 key
  final Color color;

  @override
  State<Box> createState() => _BoxState();
}

class _BoxState extends State<Box> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _counter++;
        setState(() {});
      },
      child: GestureDetector(
        onTap: () {
          _counter++;
          setState(() {});
        },
        child: Container(
          width: 80,
          height: 80,
          color: widget.color,
            child: Text("$_counter"),
          ),
      ),
    );
  }
}

把以上代码运行起来,再从上往下依次点击1、2、3次,我们会得到这么一个页面

此时我们再把_MyHomeState中的builder方法里的Box(Colors.yellow)注释掉,再hot reload一下,各位读者可以猜下页面会变成什么样

js 复制代码
class _MyHomeState extends State<MyHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: [
            Box(Colors.red),
            // Box(Colors.yellow),
            Box(Colors.blue),
          ],
        ),
      ),
    );
  }
}

如果各位读者像我一样对flutter的key不甚了解,可能会认为,页面上从上往下依次是:红1、蓝3,然而页面变成了这样

为什么会变成这样呢,这正是因为没有指定key导致的。如下图所示,我们在创建widget树的时候也会创建对应的element树,而状态是保存在elemnet树中的

当我们删除了黄色的box之后,蓝色的box就顺理成章上移动一格,匹配到右边的的state = 2的box element。而state = 3的boxelement因为找不到对应的widget也被释放掉了。

正是因为上图所说没匹配到的elemnet被释放了,我们如果把之前注释的代码加回来,再hot reload一下,得到的不是红1、黄2、蓝3,而是红1、黄2、蓝0(初始值为0)

添加了key的情况下

简单修改代码(26、27、28、37行),给Box传递参数key

js 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: MyHome(),
    ),
  );
}

class MyHome extends StatefulWidget {
  const MyHome({super.key});

  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: [
            Box(Colors.red, key: ValueKey(1),),
            Box(Colors.yellow, key: ValueKey(2),),
            Box(Colors.blue, key: ValueKey(3),),
          ],
        ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  const Box(this.color, {super.key});
  final Color color;

  @override
  State<Box> createState() => _BoxState();
}

class _BoxState extends State<Box> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _counter++;
        setState(() {});
      },
      child: GestureDetector(
        onTap: () {
          _counter++;
          setState(() {});
        },
        child: Container(
          width: 80,
          height: 80,
          color: widget.color,
          child: Text("$_counter"),
        ),
      ),
    );
  }
}

运行程序,从上往下分别点击1、2、3次,得到红1黄2蓝3

此时再把黄色的box注释掉,hot reload一下,就会得到红1蓝3,符合我们的预期

这是因为加了key之后,widget和element不再通过顺序匹配了,而是通过key来匹配,所以这次是key=2的element被释放了

相关推荐
子非鱼94273 小时前
07-Flutter 鸿蒙实战 07:故事集列表与缓存设计
学习·flutter·缓存·华为·harmonyos
子非鱼94276 小时前
08-Flutter 鸿蒙实战 08:故事详情页,编辑、删除、重新生成与底部弹层
flutter·华为·harmonyos
子非鱼94276 小时前
06-Flutter 鸿蒙实战 06:上传后处理流程,照片识别、故事生成和状态刷新
学习·flutter·华为·harmonyos
sTone873759 小时前
写时复制COW的第一性理解
android·c++·flutter
nicepainkiller9 小时前
codex 逆向 flutter
flutter·flutter 逆向
帅次9 小时前
Android 高级工程师面试:Flutter 路由导航 近1年高频追问 18 题
android·flutter·面试
浮江雾10 小时前
Flutter第七节-----快捷键创建组件与flutter中的点击事件
flutter
想你依然心痛19 小时前
【共创季稿事节】HarmonyOS 7.0 应用框架(ArkUI-X)跨平台能力深度探索
flutter·react native·arkui-x·跨平台渲染·harmonyos 7.0·arkrender·组件兼容性
SoaringHeart1 天前
Flutter最佳实践:键盘辅助视图输入框天添加图片附件
前端·flutter
心中有国也有家1 天前
AtomGit Flutter 鸿蒙客户端:Canvas 绘制进阶-路径、渐变与混合模式
android·javascript·flutter·华为·harmonyos