第一段代码实现的内容:创建了3个块,随机3个颜色,每次点击按钮时,把第一个块删除
- import 'dart:math';
- import 'package:flutter/material.dart';
- import 'package:flutter_one/demo.dart';
- void main() {
- runApp(const App());
- }
- class App extends StatelessWidget {
- const App({Key? key}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- return const MaterialApp(
- home: KeyDemo(),
- );
- }
- }
- class KeyDemo extends StatefulWidget {
- const KeyDemo({Key? key}) : super(key: key);
- @override
- State<KeyDemo> createState() => _KeyDemoState();
- }
- class _KeyDemoState extends State<KeyDemo> {
- // 生成三个无状态的块
- List<Widget> items = [
- StlItem('1'),
- StlItem('2'),
- StlItem('3')
- ];
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('KeyDemo'),
- centerTitle: true,
- ),
- body: Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: items,
- ),
- floatingActionButton: FloatingActionButton(
- child: Icon(Icons.add),
- onPressed: (){
- setState(() {
- items.removeAt(0); // 点击按钮把第一个删除
- });
- }
- ),
- );
- }
- }
复制代码 先调用无状态的StatelessWidget ,当删除发生时看看效果
- class StlItem extends StatelessWidget {
- 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) {
- return Container(
- 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')
- ];
- // 有状态
- class StfulItem extends StatefulWidget {
- final String title;
- StfulItem(this.title,{Key? key}) : super(key: key);
- @override
- State<StfulItem> createState() => _StfulItemState();
- }
- class _StfulItemState extends State<StfulItem> {
- // 随机的颜色
- final color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1.0);
- @override
- Widget build(BuildContext context) {
- return Container(
- 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: const ValueKey('1'),),
- StfulItem('2',key: const ValueKey('2'),),
- StfulItem('3',key: const ValueKey('3'),)
- ];
复制代码 key的原理
- Key本身是一个抽象类,有一个工厂构造方法,创建ValueKey
- 直接子类主要有:LocalKey 和 GlobalKey
- GlobalKey:帮助我们访问某个Widget的信息
- LocalKey :它用来区别哪个Element保留,哪个Element要删除
- ValueKey 以值作为参数(数字、字符串)
- ObjectKey:以对象作为参数
- UniqueKey:创建唯一标识
复制代码 GlobalKey利用
- import 'package:flutter/material.dart';
- class GlobalKeyDemo extends StatelessWidget {
- // 定义:GlobalKey<拿谁的数据> 变量 = GlobalKey();
- final GlobalKey<_childPageState> _globalKey = GlobalKey();
- GlobalKeyDemo({Key? key}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('GlobalKeyDemo'),
- ),
- body: childPage(
- key: _globalKey,
- ),
- floatingActionButton: FloatingActionButton(onPressed: (){
- // _globalKey 就能访问到 _childPageState 中的属性,进行修改
- _globalKey.currentState!.setState((){
- _globalKey.currentState!.data = 'hello word';
- _globalKey.currentState!.count++;
- });
- },
- child: const Icon(Icons.add),),
- );
- }
- }
- class childPage extends StatefulWidget {
- const childPage({Key? key}):super(key: key);
- @override
- State<childPage> createState() => _childPageState();
- }
- class _childPageState extends State<childPage> {
- int count = 0;
- String data = 'heelo';
- @override
- Widget build(BuildContext context) {
- return Column(
- children: [
- Text(count.toString()),
- Text(data),
- ],
- );
- }
- }
复制代码 除了定义GlobalKey外,还可以利用InheritedWidget数据共享。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |