Flutter-Key及GlobalKey的使用

1.Key的原理

什么Key?

先上代码:

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: KeyDemo(),
    );
  }
}

我们看到代码const MyApp({super.key}); 这个super.key 代表了什么?

我们通过一个案例来了解Key的原理

下面是KeyDemo()代码:

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

  @override
  State createState() => _KeyDemoState();
}
class _KeyDemoState extends State<KeyDemo> {
  List<Widget> items = [
    StfulItem(
      '1111',
    ),
    StfulItem(
      '2222',
    ),
    StfulItem(
      '3333',
    ),
  ];
  @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.add),
        onPressed: () {
          items.removeAt(0);
          setState(() {});
        },
      ),
    );
  }
}

我们看到代码floatingActionButton按钮在点击的时候,移除了items.removeAt(0);块。
刷新了UI setState(() {})。

分割线 StfulItem 组件代码:

class StfulItem extends StatefulWidget {
  final String title;

  StfulItem(this.title, {Key? key}) : super(key: key);

  @override
  _StfulItemState 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,
      color: color,
      child: Text(widget.title),
    );
  }
}


运行效果:

Flutter-Key及GlobalKey的使用
我们看到虽然111,222被移除了,但是颜色一直到上绿色在一个没有变化。这不是我们要的效果。

怎么解决一个问题呢,我们只要在item中加入key的使用代码如下:

List<Widget> items = [
    StfulItem(
      '1111',
      key: ValueKey(1111) 
    ),
    StfulItem(
      '2222',key: ValueKey(2222) 
    ),
    StfulItem(
      '3333',key: ValueKey(3333) 
    ),
  ];

就能解决这个问题,看运行结果:
Flutter-Key及GlobalKey的使用
运行结果就能达到我们的预期。

还有一个方案能解决问题:

直接上代码:

class StfulItem extends StatefulWidget {
  final String title;

  StfulItem(this.title, {Key? key}) : super(key: key);
  final color = Color.fromRGBO(
      Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1.0);
  @override
  _StfulItemState createState() => _StfulItemState();
}

把随机color 放到StfulIte -> mStatefulWidget 内部,然后(key: ValueKey(1111) 删掉 )运行:

Flutter-Key及GlobalKey的使用

为什么只有在class _StfulItemState extends State<StfulItem> 中color会出现这个问题呢?

现在进入StatefulWidget 源码查看:

Flutter-Key及GlobalKey的使用
查找到 “canUpdate”:

Flutter-Key及GlobalKey的使用
对比oldWidget 和 newWidget 的两个参数 key和 runtimeType 是否相同,如果没变化就不更新widget树。

小结:

key的原理:

  1. Key本身是一个抽象类。有一个工厂构造方法。创建ValueKey
  2. 直接子类主要有:LocalKey和GlobalKey
  3. GlobalKey:帮助我们访问莫个Widget的信息。
  4. LocalKey:它用来区别那个Element要保留,那个Element要删除!diff算法的核心所在。
    • valueKey:以值作为参数(数字,字符串)
    • Object:以对象作为参数
    • UniqueKey:(创建唯一标识)

2.GlobalKey

GlobalKey的使用

直接上案例:

class GlobalKeyDemo extends StatelessWidget {
  GlobalKeyDemo({Key? key}) : super(key: key);
  final GlobalKey<_ChildPageState> _globalKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    print('GlobalKeyDemoBuild');
    return Scaffold(
      appBar: AppBar(
        title: const Text('GloableKeyDemo'),
      ),
      body: ChildPage(
        key: _globalKey,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _globalKey.currentState!.data =
              'old:${_globalKey.currentState!.count}';
          _globalKey.currentState!.count++;
          _globalKey.currentState!.setState(() {});
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

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

  @override
  State 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),
        ],
      ),
    );
  }
}

核心内容是:

1:final GlobalKey<\_ChildPageState> \_globalKey = GlobalKey();

2:key: \_globalKey,

3:\_globalKey.currentState!.data = 'old:\${\_globalKey.currentState!.count}'; \_globalKey.currentState!.count++;

运行结果就是打印:新旧状态currentState的count的数字

Flutter-Key及GlobalKey的使用

原文链接:https://juejin.cn/post/7242965902878113853 作者:可乐泡枸杞

(0)
上一篇 2023年6月11日 上午10:10
下一篇 2023年6月11日 上午10:20

相关推荐

发表回复

登录后才能评论