在Flutter开发中,经常需要封装自定义组件,封装后的组件需要在父界面调用刷新这个子组件,并且是希望在父组件不刷新的情况下刷下子组件,本文介绍使用GlobalKey来实现。

实现方案

  • 子组件需要是StatefulWidget
  • 需要在父组件定义一个GlobalKey,并且传递给子组件的Key属性
  • 然后在父组件通过类似 globalKey.currentState.childFn(); 来调用

代码

  • 子组件代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class ChildWidget extends StatefulWidget {
  const ChildWidget({Key? key}) : super(key: key);

  @override
  State<ChildWidget> createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  int value = 0;
  void click() {
    setState(() {
      value += 1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.blueAccent,
      child: Center(
        child: Text(
          '$value',
          style: const TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}
  • 父组件代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class ParentWidget extends StatelessWidget {
  ParentWidget({Key? key}) : super(key: key);
  GlobalKey<_ChildWidgetState> childController = GlobalKey();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: Center(
        child: Column(
          children: [
            const Spacer(),
            ChildWidget(
              key: childController,
            ),
            const SizedBox(
              height: 10,
            ),
            const Text('lickscreen.com'),
            const SizedBox(
              height: 10,
            ),
            TextButton(
              onPressed: () {
                childController.currentState?.click();
              },
              child: const Text('点击+1'),
            ),
            const Spacer(),
          ],
        ),
      )),
    );
  }
}

效果

call-child-widget-method-demo

完整代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter call child widget method',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ParentWidget(),
    );
  }
}

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

  @override
  State<ChildWidget> createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  int value = 0;
  void click() {
    setState(() {
      value += 1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.blueAccent,
      child: Center(
        child: Text(
          '$value',
          style: const TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}

class ParentWidget extends StatelessWidget {
  ParentWidget({Key? key}) : super(key: key);
  GlobalKey<_ChildWidgetState> childController = GlobalKey();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: Center(
        child: Column(
          children: [
            const Spacer(),
            ChildWidget(
              key: childController,
            ),
            const SizedBox(
              height: 10,
            ),
            const Text('lickscreen.com'),
            const SizedBox(
              height: 10,
            ),
            TextButton(
              onPressed: () {
                childController.currentState?.click();
              },
              child: const Text('点击+1'),
            ),
            const Spacer(),
          ],
        ),
      )),
    );
  }
}