概述
Flutter Key的原理和使用(一) 没有Key会发生什么
Flutter Key的原理和使用(二) Widget 和 Element 的对应关系
Flutter Key的原理和使用(三) LocalKey的三种类型
Flutter Key的原理和使用(四) GlobalKey 的用法
Flutter Key的原理和使用(五) 需要key的实例:可拖动改变顺序的Listview
上一章,因为标题的原因哈,没有介绍到关于GlobalKey的内容,今天来讲一讲GlobalKey.
GlobalKey是在整个应用程序中唯一的键。
我们之前讲到,LocalKey是局部键,所以出现层级改变的时候:
Column(
children: [
Box(Colors.red, key: ValueKey(1)),
Center(child: Box(Colors.red, key: ValueKey(2))),
],
)
可以看到红色的数字从3变成了0,状态丢失了.
这时候,我们就要用到globalKey.我们前面也提过,GlobalKey必须是全局唯一的,所以即使widget从tree中的位置改变了,也依然能够找到它.
GlobalKey的使用
使用GlobalKey
不应该在每次build
的时候重建GlobalKey
, 它应该是State拥有的长期存在的对象.
所以我们应该先定义一个GlobalKey:
final GlobalKey _globalKey= GlobalKey();
将ValueKey替换成GlobalKey
这个数字太小了,我稍微改一下代码, 放大数字,并改成点击数字执行加1操作.并将Column改成Row:
Row(
children: [
Box(Colors.blue, key: ValueKey(1)),
Box(Colors.red, key: _globalKey),
],
)
得到如下的效果:
可以看到,使用globalKey的widget的状态被完美的保存了下来.
使用ValueKey的没有保留之前的状态是因为Widget Tree
和Element Tree
做对应关系的时候,因为类型改变无法对应,状态就被丢弃了.
GlobalKey的方法
我们可以通过GlobalKey来找到对应的widget,甚至是state等更多相关的东西.
可以看到,global对象提供了几个方法,我们主要用到的就是前三个,可以通过globalKey来找到对应的BuildContext
,State
以及Widget
.
获取对应的state
比如我们可以通过这个globalKey
来找到对应的按钮中的数字,我们打印一下看一看:
对应的代码:
floatingActionButton: FloatingActionButton(
onPressed: () {
print((_globalKey.currentState as _BoxState).count);
},
child: Icon(Icons.wifi_protected_setup),
)
可以看到,上面我进行了一个类型转换,因为globalKey
是任何widget都可以使用的,flutter在运行之前并不知道具体是哪个widget用到了它,所以我们这要转换成对应的类型.
那如果我们想改变里面的值呢,是否可以做到呢?
我们改变一下onPress
的代码:
onPressed: () {
final state = _globalKey.currentState as _BoxState;
state.count++;
print(state.count);
state.setState(() {});
}
切记,一定要进行setState操作,来触发Ui的刷新,否则值会修改,但是没有体现在UI上.
更好的写法是
state.setState(() {
state.count++;
});
推荐把setState需要刷新的对象放入这个大括号{}内,因为在实际开发中,并不是每次有对象变化的时候多需要刷新UI的,如果能够按照规范将需要刷新的对象放到setState中,等到需求变更,代码需要修改的时候,setState中是空的时候,我们就知道不需要刷新UI了,就可以删除掉这个setState.
反之,如果是写到外面,当我们把需要刷新的对象的代码删除掉的时候,不知道这个setState到底还有没有用(毕竟实际我们可能是多人开发,也可能自己以前写的代码不记得了),就导致了额外的刷新操作.
当然,其实上述操作也不是推荐的做法,一般都是由自己内部来管理它的状态,如果有多个widget共用的话,则应该进行变量提示
操作,把变量写到外层.
获取对应的widget
刚才我们也看到了,除了currentState
,它还有一些别的东西.
比如currentWidget
,当然我们代码对应的类型也要做改变了.
onPressed: () {
final widget = _globalKey.currentWidget as Box;
print(widget.color);
}
比如这里,因为widget是Box,所以类型转换为Box. 通过currentWidget
,我们就可以得到对应的widget
中的属性,例如此处的color.
获取对应的context
通过currentContext
,可以获得对应的context
,context
其实指的就是element
.
在第二章中我们介绍到了element tree
,并没有详细说element
.Element
的作用还是比较多的.
比如我想知道对应组件的尺寸,位置.这其实都是难以获得的信息.
final renderBox = _globalKey.currentContext!.findRenderObject() as RenderBox;
此处,我们通过currentContext!.findRenderObject
找到了对应的renderObject
,RenderObject
的类型还是比较多的.因为我们此处的Box
刚好是RenderBox
, 所以将类型转换为RenderBox
.
可以看到renderBox
有一个对应的size
方法,通过它就可以拿到对应widget的尺寸.
如果想拿到它的位置信息的话,可以通过
renderBox.localToGlobal(Offset.zero);
来拿到对应widget的左上角距离屏幕左上角的坐标信息.
看一下分别打印的信息:
I/flutter ( 2158): Size(100.0, 100.0) //对应widget的尺寸
I/flutter ( 2158): Offset(100.0, 80.0) //对应widget的坐标
小结.
最后做一个简单的总结
本章主要介绍了globalKey的两种用法,两种用法都是先声明一个globalKey,再把这个globalKey传给想要放到的widget里面.
第一种用法,保证有了globalKey的widget可以随便改变它在Wdiget Tree中的位置,而它的状态不会丢失.
第二种用法,相当于通过这个key将widget暴露了出来,借助它就可以利用类似于getElementById
之类的方式去找到它各种各样的东西:
- currentContext: 可以找到包括renderBox在内的各种element有关的东西
- currentWidget: 可以得到widget的属性
- currentState: 可以得到state里面的变量.
最后
以上就是紧张往事为你收集整理的Flutter Key的原理和使用(四) GlobalKey 的用法的全部内容,希望文章能够帮你解决Flutter Key的原理和使用(四) GlobalKey 的用法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复