[Flutter]理解Widget-Key的作用

这里主要是理解在Widget中key的作用/用途。
import 'dart:math';

import 'package:flutter/material.dart';

/// 这里主要是理解在Widget中key的作用/用途。
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: _MyHomePage(),
    );
  }
}

typedef ItemBuilder = Widget Function(String name);

class _MyHomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<_MyHomePage> {
  final List<String> _names = ["aaa", "bbb", "ccc"];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Test'),
      ),
      body: Row(
        children: [
          // StatelessWidget的Key为null。
          _buildRowChild((name) => ListItemLess(name)),
          // StatelessWidget的Key与数据键相对应。
          _buildRowChild(
              (name) => ListItemLess(name, key: ValueKey('Less' + name))),
          // StatefulWidget的Key为null。
          _buildRowChild((name) => ListItemFul(name)),
          // StatefulWidget的Key与数据键相对应。
          _buildRowChild(
              (name) => ListItemFul(name, key: ValueKey('Ful' + name))),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.delete),
        onPressed: () {
          setState(() {
            _names.removeAt(0);
          });
        },
      ),
    );
  }

  Widget _buildRowChild(ItemBuilder itemBuilder) {
    return Expanded(
      child: ListView(
        //children: _names.map((name) => ListItemLess(name)).toList(),
        children: _names.map(itemBuilder).toList(),
      ),
    );
  }
}

class ListItemLess extends StatelessWidget {
  ListItemLess(this.name, {super.key});
  final String name;
  final Color randomColor = Color.fromARGB(
      255, Random().nextInt(256), Random().nextInt(256), Random().nextInt(256));
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 80,
      child: Text(name),
      color: randomColor,
    );
  }
}

class ListItemFul extends StatefulWidget {
  const ListItemFul(this.name, {super.key});
  final String name;
  @override
  _ListItemFulState createState() => _ListItemFulState();
}

class _ListItemFulState extends State<ListItemFul> {
  final Color randomColor = Color.fromARGB(
      255, Random().nextInt(256), Random().nextInt(256), Random().nextInt(256));
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 80,
      child: Text(widget.name),
      color: randomColor,
    );
  }
}

运行结果如下图所示:

​​​​​​​   

/// 运行并依次点击删除两次, 根据情况可以发现其更新结果:
/// (1) StatelessWidget不管是否设置了Key或者前后Key是否相同, 其背景色都没有复用;
/// (2) StatefulWidget未设置Key的时候, 其背景色不变, 但是数据向上移了;
/// (3) StatefulWidget设置Key的时候, 在更新过程中根据key进行了diff算法,
/// 在相同Key的前后进行对比时, 发现bbb对应的Element和ccc对应的Element会继续复用,
/// 那么就会删除之前aaa对应的Element, 而不是直接删除最后一个Element 。
///
///
/// 官方对Widget的说明:
/// Flutter的Widgets的灵感来自React, 中心思想是构造你的UI使用这些Widgets。
/// Widget使用配置和状态, 描述这个View(界面)应该长什么样子。
/// 当一个Widget发生改变时, Widget就会重新build它的描述, 框架会和之前的描述进行对比,
/// 来决定使用最小的改变(minimal changes)在渲染树中, 从一个状态到另一个状态。
///
///
/// 自己对Widget的理解:
/// Widget就是一个个描述文件, 这些描述文件在我们进行状态改变时会不断的build。
/// 但是对于渲染对象来说, 只会使用最小的开销来更新渲染界面。
///
///
/// 参考链接:  Flutter的Widget-Element-RenderObject  。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值