📜  Flutter – Widgets 中的 Key 概念

📅  最后修改于: 2021-09-23 06:43:36             🧑  作者: Mango

在本文中,我们将研究密钥以及何时何地使用它们。所以你可能会问什么是钥匙?好吧,当小部件在小部件树中移动时,键是用来保存状态的。它用于在修改集合时保留用户滚动位置或保持状态。如果整个小部件子树是无状态的,则不需要密钥。现在让我们研究何时使用这些键。

众所周知,当小部件围绕小部件子树移动时,我们使用键来保留状态。因此,基本上,无状态小部件中不需要键,但有状态小部件中需要。

为了解释按键,我们将创建一个基本应用程序,在该应用程序中,点击按钮时,框将交换颜色。颜色的值将使用键存储。以下代码是在不使用密钥的情况下创建的应用程序。

无状态小部件树:

在此代码中,我们使用无状态小部件创建了应用程序。这里创建了一个 PositionedTiles 类。您在此代码中看到的注释是用于生成唯一颜色以随机生成框的颜色。点击按钮时, swapTiles函数被激活,然后进行交换。 onTap 按钮是底部的笑脸。

Dart
import 'package:flutter/material.dart';
import 'dart:math';
  
void main() => runApp(new MaterialApp(home: PositionedTiles()));
  
class PositionedTiles extends StatefulWidget{
  @override
  State createState() => PositionedTilesState();
}
  
class PositionedTilesState extends State{
  late List tiles;
  
  @override
  void initState(){
    super.initState();
    tiles = [
      StatelessColorfulTile(),
      StatelessColorfulTile(),
    ];
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("GEEKSFORGEEKS"),
        backgroundColor: Colors.green,
      ) ,
      body: SafeArea(child: Row(children: tiles)),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.sentiment_very_satisfied), onPressed: swapTiles),
    );
  }
  
  swapTiles(){
    setState(() {
      tiles.insert(1, tiles.removeAt(0));
    });
  }
}
  
class StatelessColorfulTile extends StatelessWidget {
  Color myColor = UniqueColorGenerator.getColor();
  @override
  Widget build(BuildContext context) {
    return Container(
        color: myColor, child: Padding(padding: EdgeInsets.all(70.0)));
  }
}
  
//this code snippet tells you how UniqueColorGenerator works
class UniqueColorGenerator {
  static List colorOptions = [
    Colors.blue,
    Colors.red,
    Colors.green,
    Colors.yellow,
    Colors.purple,
    Colors.orange,
    Colors.indigo,
    Colors.amber,
    Colors.black,
  ];
  static Random random = new Random();
  static Color getColor() {
    if (colorOptions.length > 0) {
      return colorOptions.removeAt(random.nextInt(colorOptions.length));
    } else {
      return Color.fromARGB(random.nextInt(256), random.nextInt(256),
          random.nextInt(256), random.nextInt(256));
    }
  }
}


Dart
import 'package:flutter/material.dart';
import 'dart:math';
  
void main() => runApp(new MaterialApp(home: PositionedTiles()));
  
class PositionedTiles extends StatefulWidget{
  @override
  State createState() => PositionedTilesState();
}
  
class PositionedTilesState extends State{
  late List tiles;
  
  @override
  void initState(){
    super.initState();
    tiles = [
      StatefulColorfulTile(key: UniqueKey()),
      StatefulColorfulTile(key: UniqueKey()),
    ];
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
        title: Text("GEEKSFORGEEKS"),
        backgroundColor: Colors.green,
        ) ,
      body: SafeArea(child: Row(children: tiles)),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.sentiment_very_satisfied), onPressed: swapTiles),
    );
  }
  
  swapTiles(){
    setState(() {
      tiles.insert(1, tiles.removeAt(0));
    });
  }
}
  
class StatefulColorfulTile extends StatefulWidget {
  StatefulColorfulTile({required Key key}) : super(key: key);
  @override
  State createState() => StatefulColorfulTileState();
}
class StatefulColorfulTileState extends State {
  late Color myColor;
  @override
  void initState() {
    super.initState();
    myColor = UniqueColorGenerator.getColor();
  }
  @override
  Widget build(BuildContext context) {
    return Container(
        color: myColor,
        child: Padding(
          padding: EdgeInsets.all(70.0),
        ));
  }
}
  
class UniqueColorGenerator {
  static List colorOptions = [
    Colors.blue,
    Colors.red,
    Colors.green,
    Colors.yellow,
    Colors.purple,
    Colors.orange,
    Colors.indigo,
    Colors.amber,
    Colors.black,
  ];
  static Random random = new Random();
  static Color getColor() {
    if (colorOptions.length > 0) {
      return colorOptions.removeAt(random.nextInt(colorOptions.length));
    } else {
      return Color.fromARGB(random.nextInt(256), random.nextInt(256),
          random.nextInt(256), random.nextInt(256));
    }
  }
}


输出:

无状态小部件树

在这里您可以看到颜色正在发生变化,但是当我们将其更改为 Stateful 小部件时,代码将正常工作,但应用程序上不会显示任何内容。但是当我们在 Stateful 小部件中使用这里的键时,应用程序将正常工作。下面显示的以下代码是直接使用键的。

有状态的小部件树:

在此代码中,您可以看到我们使用了此处的键功能,因此应用程序运行良好。其余代码相同,这里仅新增Key特性。

Dart

import 'package:flutter/material.dart';
import 'dart:math';
  
void main() => runApp(new MaterialApp(home: PositionedTiles()));
  
class PositionedTiles extends StatefulWidget{
  @override
  State createState() => PositionedTilesState();
}
  
class PositionedTilesState extends State{
  late List tiles;
  
  @override
  void initState(){
    super.initState();
    tiles = [
      StatefulColorfulTile(key: UniqueKey()),
      StatefulColorfulTile(key: UniqueKey()),
    ];
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
        title: Text("GEEKSFORGEEKS"),
        backgroundColor: Colors.green,
        ) ,
      body: SafeArea(child: Row(children: tiles)),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.sentiment_very_satisfied), onPressed: swapTiles),
    );
  }
  
  swapTiles(){
    setState(() {
      tiles.insert(1, tiles.removeAt(0));
    });
  }
}
  
class StatefulColorfulTile extends StatefulWidget {
  StatefulColorfulTile({required Key key}) : super(key: key);
  @override
  State createState() => StatefulColorfulTileState();
}
class StatefulColorfulTileState extends State {
  late Color myColor;
  @override
  void initState() {
    super.initState();
    myColor = UniqueColorGenerator.getColor();
  }
  @override
  Widget build(BuildContext context) {
    return Container(
        color: myColor,
        child: Padding(
          padding: EdgeInsets.all(70.0),
        ));
  }
}
  
class UniqueColorGenerator {
  static List colorOptions = [
    Colors.blue,
    Colors.red,
    Colors.green,
    Colors.yellow,
    Colors.purple,
    Colors.orange,
    Colors.indigo,
    Colors.amber,
    Colors.black,
  ];
  static Random random = new Random();
  static Color getColor() {
    if (colorOptions.length > 0) {
      return colorOptions.removeAt(random.nextInt(colorOptions.length));
    } else {
      return Color.fromARGB(random.nextInt(256), random.nextInt(256),
          random.nextInt(256), random.nextInt(256));
    }
  }
}

输出:

有状态的小部件树

现在从上面的例子可以清楚地知道在哪里添加它们。答案很简单,如果您必须使用有状态小部件,那么您必须使用密钥,否则无需使用它们。

现在flutter有很多种 Keys 。所有这些都在下面讨论过:

Flutter的键类型:

  • 价值键:当必须将价值键分配给一些不变的和非凡的东西时,就会使用价值键。例如,在待办事项列表中,输入的文本就是值。
  • 对象键:对象键用于任何单个字段,例如姓名或生日,它们可能在两个以上的人中相同,但对于每个人或每个数据组合都是唯一的。
  • 唯一键:当有许多具有相同激励的小部件时使用唯一键,那么我们必须使用将每个小部件定义为唯一小部件。我们在代码中使用它也是因为我们不知道在组装小部件之前会为它分配什么随机颜色。
  • 全局键:全局键的用途在于它包含可由代码中存在的其他小部件访问的数据。如果您不想与其他小部件共享它,那么您必须使用 Global Key 保存状态形式并且不允许其他小部件访问存储在其中的数据。

所以,总而言之,我们可以说键是flutter中一个非常好的特性。它仅适用于 Stateful 小部件以及在修改集合时使用它来存储当前状态的值的目的。