这里主要是理解在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 。