分析key的原理,渲染机制
问题引导:首先我们先来看以下的一个demo例子:
import 'package:flutter/material.dart';
import 'dart:math';
//key本身是一个抽象类 flutter的增量更新,会根据elelment和widget之间的key做对比,来判别是否更新
//ValueKey、ObjectKey、UniqueKey
class KeyDemo extends StatefulWidget {
@override
_State createState() => _State();
}
class _State extends State<KeyDemo> {
List<Widget> _widgetss = [
JItem(text: '111',),
JItem(text: '222',),
JItem(text: '333',),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
SizedBox(height: 100,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _widgetss,
),
SizedBox(height: 100,),
FloatingActionButton(onPressed: (){
setState(() {
_widgetss.removeAt(0);
});
}),
],
),
);
}
}
class JItem extends StatefulWidget {
final String text;
JItem({
this.text,
});
@override
_JItemState createState() => _JItemState();
}
class _JItemState extends State<JItem> {
final _color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
@override
Widget build(BuildContext context) {
return Container(color: _color,child: Text('1111'),width: 100,height: 100,);
}
}
run
![](https://img.haomeiwen.com/i13273079/ffb97f955a55c2ea.png)
点击一次按钮:思考为什么粉色的方块消息了呢,而不是褐色方块消息呢?????
![](https://img.haomeiwen.com/i13273079/60c0b8de96740f05.png)
点击一次按钮:思考为什么褐色的方块消息了呢,而不是紫色方块消息呢?????
![](https://img.haomeiwen.com/i13273079/de93e99371189db5.png)
原理探究:渲染机制
Widget树对应着element树,当widget树中的第一个widget消失的时候,那么element中的第一个将会去查找widget树中的第二个widget,当判断类型相同且key值一样时,这时候,就会产生element重用的机制,即第二个widget重用了第一个element的属性,即颜色色值,当然widget中的data发生了改变,所以产生了即将显示的widget重用了本该消失的element。而最后一个element被抛弃了
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
解决思路一:
我们将state中的属性值放到widget中,即element失去持有,即使重用也没关系。但此方法并不可取,
class JItem extends StatefulWidget {
final String text;
final _color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
JItem({
this.text,
});
@override
_JItemState createState() => _JItemState();
}
class _JItemState extends State<JItem> {
@override
Widget build(BuildContext context) {
return Container(color: widget._color,child: Text('1111'),width: 100,height: 100,);
}
}
解决思路一:巧用key,
通常我们会用widget设置key来建立与element的连接,这样就不会导致element的重用
ValueKey:适用于比较单一的区别判断,
class JItem extends StatefulWidget {
final String text;
JItem({this.text,Key key}) : super(key : key);
@override
_JItemState createState() => _JItemState();
}
List<Widget> _widgetss = [
JItem(text: '111',key: ValueKey('111'),),
JItem(text: '222',key: ValueKey('222'),),
JItem(text: '333',key: ValueKey('333'),),
];
ObjectKey:适用于组合类型的区别判断,
UniqueKey: 唯一key
PageStorageKey :这是一个很特殊的key,它保存了用户滚动的位置,这样app可以保存用户滚动的位置给下次用户打开的时候直接到上次滚动的位置。
GlobalKey:可以在app的任何地方更换父widget而不会丢失状态、它可以用来从完全不同的widget树里面访问数据
class _State extends State<KeyDemo> {
final GlobalKey<_JItemState> _globalKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
SizedBox(height: 100,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
JItem(text: '111',key: _globalKey,),
],
),
SizedBox(height: 100,),
FloatingActionButton(onPressed: (){
setState(() {
_globalKey.currentState.setState(() {
_globalKey.currentState._color = Colors.orange;
});
});
}),
],
),
);
}
}
网友评论