1.Key

参考:https://api.flutter.dev/flutter/widgets/Widget/key.html

控制一个widget该如何替换掉树中的另一个widget:如果两个widget的runtimeType 和 key都相等(==),那么会让旧widget所对应的旧element转而指向新widget(即调用element.update);否则,旧element会被从树中移除,然后根据新widget来生成一个新element,并将该新element插入到树中。

Key的用途

参考:https://api.flutter.dev/flutter/foundation/Key-class.html

大多数时候并不需要使用key。

当需要在一个StatefulWidget集合中进行添加、删除、重排序等操作时,才是key登场的时候。

无状态组件

下面这段代码在一个Row中展示了两个彩色方片(StatelessColorfulTile),当点击按钮时,会交换两个方片的位置:

class PositionedTiles extends StatefulWidget {@overrideState<StatefulWidget> createState() => PositionedTilesState();
}class PositionedTilesState extends State<PositionedTiles> {List<Widget> tiles;@overridevoid initState() {super.initState();tiles = [StatelessColorfulTile(),StatelessColorfulTile(),];}@overrideWidget build(BuildContext context) {return Scaffold(body: Center(child: Row(children: tiles,),),floatingActionButton: FloatingActionButton(child: Icon(Icons.update),onPressed: swapTiles,),);}void swapTiles() {setState(() {tiles.insert(1, tiles.removeAt(0));});}//...}

基础知识:element树决定了页面最终展示到屏幕上的样子。但element树中只存储节点的类型,更具体的信息需要去widget树中查找。每个element会通过引用指向其对应的widget。


当交换两个widget的位置(并调用父组件PositionedTiles的setState方法)后,flutter会从上到下逐一对比widget树和element树中的每个节点,如果左右节点的类型和key一致的话(这里没有key,因此只对比类型),那么就认为该element仍然是有效的,可用复用,于是直接让element指向左边对应位置的widget——这种element的复用提高了渲染效率。而由于无状态widget的颜色信息是存储在widget中的,因此只要交换widget,无需改变element,实际显示到屏幕上就是成功交换的效果。

有状态组件

有状态组件的状态信息(如颜色)通常是存储在state中的,而state是存储在element树中的。


当交换两个widget的位置(并调用父组件PositionedTiles的setState方法)后,与前面一样,flutter会从上到下逐一对比widget树和element树中的每个节点,如果左右节点的类型和key一致的话(这里没有key,因此只对比类型),那么就认为该element仍然是有效的,可用复用,于是直接让element指向左边对应位置的widget。

但与之前不同的是,因为颜色信息存储在element树中,因此element树被复用的结果就是显示效果也不会有任何变化——仍然是widget未交换时的效果。


解决办法1:给widget指定key,如下图所示。因为key不相同,因此右边的element就不会被直接复用。flutter会在右边的element树中查找与widget类型和key都相同的element,如果找到,就会移动该element并让该element指向左边的widget,如果没有找到,则会根据widget信息创建新的element。


为了避免混淆,有必要说明一下:如果改变图中小方片(Stateful Tile)的State中的颜色,并调用小方片的setState方法的话,那么改变是可以生效的,因为是直接改变了小方片的State对象。这和上面说的改变父组件PositionedTiles的State并调用其setState是不同的情形,PositionedTiles的State就是小方片的List,setState的结果就是widget树中两个小方片的位置变了,但是因为上面所述的原因,如果不给每个小方片widget指定key的话,最后的显示效果不会改变。

解决办法2,覆写State的didUpdateWidget方法,当widget的配置发生变化时,手动更新state,例如:

///Called whenever the widget configuration changes.
void didUpdateWidget(TimePickerBar oldWidget) {super.didUpdateWidget(oldWidget);if (oldWidget.initValue != widget.initValue) {_currentTime = widget.initValue;_tempTime = DateTime.fromMillisecondsSinceEpoch(_currentTime.millisecondsSinceEpoch);}
}

Key的种类

  • ValueKey:以一个值为key。
  • ObjectKey:以一个对象为key。
  • UniqueKey:生成唯一的随机数作为key。
  • PageStorageKey:专用于存储页面滚动位置的key。
  • GlobalKey:见下一节。

2.GlobalKey

参考:https://api.flutter.dev/flutter/widgets/GlobalKey-class.html

每个globalkey都是一个在整个应用内唯一的key。

globalkey相对而言是比较昂贵的,如果你并不需要globalkey的某些特性,那么可以考虑使用Key、ValueKey、ObjectKey或UniqueKey。

用途1

允许widget在应用程序中的任何位置更改其parent而不丢失其状态。应用场景:在两个不同的屏幕上显示相同的widget,并保持状态相同。

用途2

globalkey唯一定义了某个element,它使你能够访问与element相关联的其他对象,例如buildContext、state等。应用场景:跨widget访问状态:

class MyHomePage extends StatefulWidget {MyHomePage({Key key}) : super(key: key);@override_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {final GlobalKey<SwitcherWidgetState> key = GlobalKey();@overrideWidget build(BuildContext context) {return Scaffold(body: SwitcherWidget(key: key,),floatingActionButton: FloatingActionButton(onPressed: () {key.currentState.changeState();},child: Text('切换'),),);}
}

SwitcherWidgetState中有一个changeState()方法。在SwitcherWidget组件的外部,可以通过key.currentState拿到它的状态对象,然后就可以调用其中的changeState()方法。

Flutter中的Key和GlobalKey相关推荐

  1. element中有多个合计_深入理解 Flutter 中的 Widget, Element, RenderObject

    这篇文章基于 Flutter stable v1.7 总结下 Flutter 当前的 UI 系统以及相关的概念, 在最后会通过自己组合一个 Gradient Button 按钮的方式来熟悉 Flutt ...

  2. Flutter中Widget 、Element、RenderObject角色深入分析

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天. ** 你可能需要 CSDN 网易云课堂教程 掘金 EDU学院教程 知乎 Flutter系列文章 本文章将讲述 Widg ...

  3. 【Flutter 问题系列第 22 篇】在 Flutter 中如何截取屏幕并显示到页面中,以及如何将截图保存到相册

    这是[Flutter 问题系列第 22 篇],如果觉得有用的话,欢迎关注专栏. 关于在 Flutter 中如何截取屏幕,以及如何将截图保存到相册的文章少之又少,即使有,也是错误一大片,有的甚至运行后都 ...

  4. 【译】学习Flutter中新的Navigator和Router系统

    原文:Learning Flutter's new navigation and routing system 作者:John Ryan 本文解释了Flutter新的Navigator和Router ...

  5. mvp 在 flutter 中的应用

    在 Android 应用程序开发过程中,我们经常会用到一些所谓的架构方法,如:mvp,mvvm,clean等.之所以这些方法会被推崇是因为他们可以大大的解耦我们的代码的功能模块,让我们的代码在项目中后 ...

  6. 在 Flutter 中使用 NavigationRail 和 BottomNavigationBar

    在 Flutter 中使用 NavigationRail 和 BottomNavigationBar 作者:坚果 公众号:"大前端之旅" 华为云享专家,InfoQ签约作者,阿里云专 ...

  7. Flutter中实现整个App变为灰色

    前言 为了让更多的人永远记住12月13日,各大厂都在这一天将应用变灰了. 那么接下来我们看一下Flutter是如何实现的. Flutter中实现整个App变为灰色 在Flutter中实现整个App变为 ...

  8. Flutter 中获取地理位置[Flutter专题61]

    大家好,我是坚果,公众号"坚果前端" Flutter 中获取地理位置 如今,发现用户位置是移动应用程序非常常见且功能强大的用例.如果您曾经尝试过在 Android 中实现位置,您就 ...

  9. 在Flutter中解析复杂的JSON(一篇顶十篇)

    文章目录 JSON结构#1:简单 map 访问对象 Snippet #1 : imports **Snippet #2 : **加载Json Asset(可选)** Snippet #3 : 加载响应 ...

最新文章

  1. Javascript 上课笔记
  2. c语言程序设计实验报告2,C语言程序设计实验报告2.docx
  3. fixed 定位 苹果手机输入框触发时内容全部隐藏
  4. php --魔术常量 /魔术方法
  5. [零基础学JAVA]Java SE应用部分-35.JAVA类集之四
  6. 用python编excel统计表_Python实现对excel文件列表值进行统计的方法
  7. jeecg开源项目的IDEA的部署
  8. oracle sequences优化_Oracle优化(恒生内部常规分享)
  9. MS Sql Server查询磁盘的可用空间,数据库数据文件及日志文件的大小及利用率
  10. 计算机动漫与游戏制作心得,学习课件制作的心得体会(精选10篇)
  11. 格签名困难假设: 最短向量问题SVP
  12. mysql msvcp140.dll修复_丢失msvcp140.dll怎么办
  13. MySQL查询指令示例---初学者必看
  14. 水性建筑涂料行业调研报告 - 市场现状分析与发展前景预测
  15. 安利几款超好用,不容错过的APP
  16. 学堂在线《工程伦理》第八章课后习题及答案(仅供参考)
  17. Docker从入门到上瘾,万字终极指南!
  18. ppt文件如何压缩到最小?
  19. 【区块链开发】区块链农产品溯源App
  20. A2开发版简介 ----学习笔记

热门文章

  1. 一个io读写指定后缀名的E盘下的全部文件拷贝指定位置盘符
  2. Autodesk Flame2016、Flame2018、Flame2020系统要求以及安装测试
  3. SpringBoot整合Redisson
  4. 问题及解答---表格(2020.7.20--至今)
  5. go读取pptx文件
  6. MFC基于对话框添加图片控件
  7. 腾达无线网卡linux怎么安装,怎么在linux系统安装腾达u1网卡
  8. 应用发布到移动应用商场
  9. 2018.11.01【NOIP2016】【洛谷P2831】愤怒的小鸟(状压DP)
  10. cf919的ABC(太咸nowatashi)