随意点开一个Widget
,就会发现,可以传递一个参数Key
.那这个Key到底是干啥子,有什么用呢?
Flutter是受React启发的,所以Virtual Dom的diff算法也参考过来了(应该是略有修改),在diff的过程中如果节点有Key来比较的话,能够最大程度重用已有的节点(特别在列表的场景),除了这一点这个Key也用在很多其他的地方这个以后会总结一下。总之,这里我们可以知道key能够提高性能,所以每个Widget都会构建方法都会有一个key的参数可选,贯穿着整个框架。
通常情况下,我们不需要去传递这个Key
。因为framework
会在内部自处理它,来区分不同的widgets
- 使用ObjectKey
和ValueKey
来对组件进行区分。
可以看, 和另外一个例子,这个例子是deletion: .
简单的来说,当我们使用Row
或者Column
时,想要执行一个remove
的动画
new AnimatedList( children: [ new Card(child: new Text("foo")), new Card(child: new Text("bar")), new Card(child: new Text("42")), ])
当我们移除"bar"后
new AnimatedList( children: [ new Card(child: new Text("foo")), new Card(child: new Text("42")), ])
因为我们没有定义Key,所以可能flutter并不知道,我们那个item发生了改变,所以可能发生在位置1上的动画,可能发生在其他位置。
正确的修改如下:new AnimatedList( children: [ new Card(key: new ObjectKey("foo"), child: new Text("foo")), new Card(key: new ObjectKey("bar"), child: new Text("bar")), new Card(key: new ObjectKey("42"), child: new Text("42")), ])
这样当我们移除"bar"的时候,flutter就能准确的区别到正确的位置上。
Key
虽然不是Index
,但是对于每一个元素来说,是独一无二的。 - 使用GlobalKey
- 使用
GlobalKey
的场景是,从父控件和跨子Widget
来传递状态时。 需要注意的是:不要滥用GlobalKey,如果有更好的方式的,请使用其他方式来传递状态。
这里有一个例子是 通过给Scaffold添加GolbalKey。然后通widget.GolbalKey.state来调用showSnackBar
class _MyHomePageState extends State{ final globalKey = new GlobalKey (); void _incrementCounter() { globalKey.currentState .showSnackBar(SnackBar(content: Text('I am context from Scaffold'))); } @override Widget build(BuildContext context) { return new Scaffold( key: globalKey, //... )}}
这样就可以直接从父控件调用子Widget
的状态。
推荐视频
- 还有一个场景是,过渡动画,当两个页面都是相同的Widget时,也可以使用GlobalKey。
总之框架要求同一个父节点下子节点的Key都是唯一的就可以了,GlobalKey可以保证全局是唯一的,所以GlobalKey的组件能够依附在不同的节点上。
https://www.jianshu.com/p/e9f48141218d?tdsourcetag=s_pctim_aiomsg