0


Flutter:key的作用原理(LocalKey ,GlobalKey)

第一段代码实现的内容:创建了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

数据共享。


本文转载自: https://blog.csdn.net/qq_40745143/article/details/143812543
版权归原作者 sunly_ 所有, 如有侵权,请联系我们删除。

“Flutter:key的作用原理(LocalKey ,GlobalKey)”的评论:

还没有评论