第一段代码实现的内容:创建了3个块,随机3个颜色,每次点击按钮时,把第一个块删除
import'dart:math';import'package:flutter/material.dart';import'package:flutter_one/demo.dart';voidmain(){runApp(constApp());}classAppextendsStatelessWidget{constApp({Key? key}):super(key: key);
@override
Widget build(BuildContext context){returnconstMaterialApp(
home:KeyDemo(),);}}classKeyDemoextendsStatefulWidget{constKeyDemo({Key? key}):super(key: key);
@override
State<KeyDemo>createState()=>_KeyDemoState();}class_KeyDemoStateextendsState<KeyDemo>{// 生成三个无状态的块
List<Widget> items =[StlItem('1'),StlItem('2'),StlItem('3')];
@override
Widget build(BuildContext context){returnScaffold(
appBar:AppBar(
title:constText('KeyDemo'),
centerTitle:true,),
body:Row(
mainAxisAlignment: MainAxisAlignment.center,
children: items,),
floatingActionButton:FloatingActionButton(
child:Icon(Icons.add),
onPressed:(){setState((){
items.removeAt(0);// 点击按钮把第一个删除});}),);}}
先调用无状态的
StatelessWidget
,当删除发生时看看效果
classStlItemextendsStatelessWidget{
final String title;StlItem(this.title,{Key? key}):super(key: key);// 随机的颜色
final color = Color.fromRGBO(Random().nextInt(256),Random().nextInt(256),Random().nextInt(256),1.0);
@override
Widget build(BuildContext context){returnContainer(
width:100,
height:100,
child:Text(title),
color: color,);}}
发生删除时:
删除后
总结发现,如果是无状态的
StatelessWidget
即使不传key:
StlItem(this.title,{Key? key}) : super(key: key);
也能正常删除。
下面看下有状态的
StatelessWidget
,不传key会出现什么BUG
// 第一段代码中:生成三个有状态的块
List<Widget> items =[StfulItem('1'),StfulItem('2'),StfulItem('3')];// 有状态classStfulItemextendsStatefulWidget{
final String title;StfulItem(this.title,{Key? key}):super(key: key);
@override
State<StfulItem>createState()=>_StfulItemState();}class_StfulItemStateextendsState<StfulItem>{// 随机的颜色
final color = Color.fromRGBO(Random().nextInt(256),Random().nextInt(256),Random().nextInt(256),1.0);
@override
Widget build(BuildContext context){returnContainer(
width:100,
height:100,
child:Text(widget.title),
color: color,);}}
删除前
删除后
发现问题了:我删除的是第一条数据,发现
文字1
正常删除,但是颜色怎么是把
颜色3
给删除了呢??
源码中,
StatelessWidget
和
StatefulWidget
都继承
Widget
abstract class StatefulWidget extends Widget{}
而在
Widget
中有这样一个方法,Flutter的增量渲染就是通过
canUpdate
来判断哪里需要更新数据。
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
Flutter中的3棵树中,Widget树和Element树
每创建一个
Widget
,都会有对应的
Element
当删除第一个
Widget
,
Element
就会调用
canUpdate
更新数据,
Element
是按顺序判断,它会拿
Element111
和删除后的
Widget222
进行对比
oldWidget.runtimeType == newWidget.runtimeType
旧的部件类型和新的部件类型是一样的,
oldWidget.key == newWidget.key;
旧的没有传key和新的也没传key,结果那就是
true
,增量渲染发现可以复用,
Element111
就指向了
Widget222
最后对比到
Element333
,发现
Widget
树中已经没有了,
Element333
就被删除了。
那么颜色为什么会错了,因为颜色是保存在
State
中,
State
是保存在
Element
中,所以最后一个颜色
canUpdate
时被删除了。
加上key之后解决这个BUG
List<Widget> items =[StfulItem('1',key:constValueKey('1'),),StfulItem('2',key:constValueKey('2'),),StfulItem('3',key:constValueKey('3'),)];
key的原理
Key本身是一个抽象类,有一个工厂构造方法,创建ValueKey
直接子类主要有:LocalKey 和 GlobalKey
GlobalKey:帮助我们访问某个Widget的信息
LocalKey :它用来区别哪个Element保留,哪个Element要删除
ValueKey 以值作为参数(数字、字符串)
ObjectKey:以对象作为参数
UniqueKey:创建唯一标识
GlobalKey使用
import'package:flutter/material.dart';classGlobalKeyDemoextendsStatelessWidget{// 定义:GlobalKey<拿谁的数据> 变量 = GlobalKey();
final GlobalKey<_childPageState> _globalKey =GlobalKey();GlobalKeyDemo({Key? key}):super(key: key);
@override
Widget build(BuildContext context){returnScaffold(
appBar:AppBar(
title:constText('GlobalKeyDemo'),),
body:childPage(
key: _globalKey,),
floatingActionButton:FloatingActionButton(onPressed:(){// _globalKey 就能访问到 _childPageState 中的属性,进行修改
_globalKey.currentState!.setState((){
_globalKey.currentState!.data ='hello word';
_globalKey.currentState!.count++;});},
child:constIcon(Icons.add),),);}}classchildPageextendsStatefulWidget{constchildPage({Key? key}):super(key: key);
@override
State<childPage>createState()=>_childPageState();}class_childPageStateextendsState<childPage>{
int count =0;
String data ='heelo';
@override
Widget build(BuildContext context){returnColumn(
children:[Text(count.toString()),Text(data),],);}}
除了定义
GlobalKey
外,还可以使用
InheritedWidget
数据共享。
版权归原作者 sunly_ 所有, 如有侵权,请联系我们删除。