跳转至

Key

只要继承Widget的都有一个key,Key是用来标识小部件。区分widget。

StatefulWidget的Widget和State是分开的。

Widget

@immutable
abstract class Widget extends DiagnosticableTree {
  /// Initializes [key] for subclasses.
  const Widget({ this.key });

  final Key? key;

  @protected
  @factory
  Element createElement();

  /// A short, textual description of this widget.
  @override
  String toStringShort() {
    final String type = objectRuntimeType(this, 'Widget');
    return key == null ? type : '$type-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  @override
  @nonVirtual
  bool operator ==(Object other) => super == other;

  @override
  @nonVirtual
  int get hashCode => super.hashCode;

  /// 增量渲染,改变的内容渲染,大量的内容复用,哪里改变了哪里没变通过下面方法。
  /// oldWidget和newWidget类型一样 并且key也一样
  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }

  static int _debugConcreteSubtype(Widget widget) {
    return widget is StatefulWidget ? 1 :
           widget is StatelessWidget ? 2 :
           0;
  }
}

Key是一个抽象类,有一个工厂构造方法。创建ValueKey,值是任意类型。

直接子类LocalKey,GlobalKey。

GlobalKey

GlobalKey对应某一个Widget State Element(Context)。

帮助我们访问某个Widget的信息,类似tag标记的功能。

根据key.currentState找到state,就可以使用state里面的data和调用setState(() {});方法。

import 'package:flutter/material.dart';

class GlobalKeyDemo extends StatelessWidget {
  final GlobalKey<_ChildPageState> _globalKey = 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.currentState!.setState(() {
            _globalKey.currentState!.data =
                'old' + _globalKey.currentState!.count.toString();
            _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 = 'hello';
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [Text(count.toString()), Text(data)],
      ),
    );
  }
}

自定义键盘的显示

自定义键盘使用StatefulWidget包装,通过key找到自定义键盘的state,和里面的TextEditingController、isVisible。

LocalKey

用来区别哪个Element保留,哪个Element删除。diff算法的核心所在。

  • ValueKey以值作为参数(数字,字符串)
  • ObjectKey以对象作为参数
  • UniqueKey()创建唯一标识,整个项目只有一个,不会被复用。

增量渲染对比的是Widget树和Element树。

Widget树:

  • Widget111
  • Widget222
  • Widget333

Element树:

  • Element111
  • Element222
  • Element333

当删除Widget111的时候,会调Element111的canUpdate,canUpdate里面会判断,最后Element333会被删除。

import 'dart:math';

import 'package:flutter/material.dart';

class KeyDemo extends StatefulWidget {
  const KeyDemo({Key? key}) : super(key: key);

  @override
  State<KeyDemo> createState() => _KeyDemoState();
}

class _KeyDemoState extends State<KeyDemo> {
  List<Widget> items = [
    const StfulItem(
      '1111',
      key: ValueKey(111),
    ),
    const StfulItem(
      '2222',
      key: ValueKey(222),
    ),
    const StfulItem(
      '3333',
      key: ValueKey(333),
    )
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('keyDemo'),
      ),
      body: Row(
        mainAxisAlignment: MainAxisAlignment.center, //主轴
        children: items,
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.delete),
        onPressed: () {
          setState(() {
            items.removeAt(0); //删除第一个
          });
        },
      ),
    );
  }
}

class StfulItem extends StatefulWidget {
  final String title;

  const 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,
    );
  }
}