Flutter 组件通信

lxf2023-04-19 21:12:02

前言

flutter的状态管理有provider,riverpod,getx等方案,但是在开发中,存在着大量父子组件通信并不需要进行状态管理的情况。这里介绍下组件传值常用情况

1. 父传子

父组件通过传递参数,将值给子组件

//---------------------------- ParentWidget ----------------------------

class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

  @override
  State<ParentWidget> createState() => _ParentWidgetCState();
}

class _ParentWidgetCState extends State<ParentWidget> {
  bool _active = false; //定义状态

  void _handleTapboxChanged() {
    setState(() {
      _active = !_active;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          InkWell(
            child: const Text('点击'),
            onTap: () {
              _handleTapboxChanged();
            },
          ),
          Tapbox(active: _active),//传递状态
        ],
      ),
    );
  }
}

//----------------------------- Tapbox ------------------------------

class Tapbox extends StatefulWidget {
  final bool active;
  const Tapbox({super.key, required this.active});

  @override
  State<Tapbox> createState() => _TapboxCState();
}

class _TapboxCState extends State<Tapbox> {
  @override
  Widget build(BuildContext context) {
    return Text(
      widget.active ? 'Active' : 'Inactive',
    );
  }
}

2. 子传父

父组件定义状态和改变状态的方法,并传递给子组件;子组件通过给方法传值来改变父组件的状态

//---------------------------- ParentWidget ----------------------------

class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

  @override
  State<ParentWidget> createState() => _ParentWidgetCState();
}

class _ParentWidgetCState extends State<ParentWidget> {
  bool _active = false; //定义状态

  void _handleTapboxChanged(bool newValue) {
    //定义改变状态的方法
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Tapbox( //传递状态和改变状态的方法
        active: _active,
        onChanged: _handleTapboxChanged,
      ),
    );
  }
}

//----------------------------- Tapbox ------------------------------

class Tapbox extends StatefulWidget {
  const Tapbox({super.key, required this.active, required this.onChanged});

  final bool active;
  final void Function(bool newValue) onChanged;

  @override
  State<Tapbox> createState() => _TapboxCState();
}

class _TapboxCState extends State<Tapbox> {
  void _handleTap() {
    widget.onChanged(!widget.active); //给方法传值
  }

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: _handleTap,
      child: Text(
        widget.active ? 'Active' : 'Inactive',
      ),
    );
  }
}

3. 父调用子

借助GlobalKey获取到子组件

//---------------------------- ParentWidget ----------------------------

GlobalKey<TapboxCState> childKey = GlobalKey(); //1. 创建 globalKey

class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

  @override
  State<ParentWidget> createState() => _ParentWidgetCState();
}

class _ParentWidgetCState extends State<ParentWidget> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Tapbox(
            key: childKey, // 2. 给子组件传递一个 globalKey
          ),
          InkWell(
            onTap: () {
              // 3. 通过 globalKey 的 currentState 获取方法  
              childKey.currentState
                  ?.handleTap(); 
            },
            child: const Text('点击'),
          )
        ],
      ),
    );
  }
}

//----------------------------- Tapbox ------------------------------

class Tapbox extends StatefulWidget {
  const Tapbox({super.key});

  @override
  State<Tapbox> createState() => TapboxCState();
}

class TapboxCState extends State<Tapbox> {
  void handleTap() {
    print('被调用');
  }

  @override
  Widget build(BuildContext context) {
    return const Text(
      '子组件',
    );
  }
}

4. 上下文传值(InheritedWidget)

  1. 新建persionShareDataWidget.dart
import 'package:flutter/material.dart';

class PersionShareDataWidget extends InheritedWidget {
  const PersionShareDataWidget({
    super.key,
    required this.data,
    required super.child,
  });

  final Person data; //需要在子树中共享的数据

  //提供一个 “of” 静态方法来获取其对象
  static PersionShareDataWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<PersionShareDataWidget>();
  }

  //当data发生变化时,是否通知子树中依赖data的Widget重新build
  @override
  bool updateShouldNotify(PersionShareDataWidget oldWidget) {
    return oldWidget.data != data;
  }
}

class Person{
  String name;
  int age;
  Person({required this.name, required this.age});
}
  1. 使用
import 'package:flutter/material.dart';
import 'persionShareDataWidget.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const GrandFather(),
    );
  }
}

class GrandFather extends StatefulWidget {
  const GrandFather({super.key});

  @override
  State<GrandFather> createState() => _GrandFatherState();
}

class _GrandFatherState extends State<GrandFather> {
  Person person = Person(name: '张三', age: 18);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PersionShareDataWidget(
          data: person,
          child: Column(
            children: [
              const Text('祖先组件'),
              const Child(),
              ElevatedButton(
                child: const Text("Increment"),
                //更新数据
                onPressed: () => setState(() {
                  person = Person(name: '李四', age: 19);
                }),
              )
            ],
          )),
    );
  }
}

class Child extends StatefulWidget {
  const Child({super.key});

  @override
  State<Child> createState() => _ChildState();
}

class _ChildState extends State<Child> {
  @override
  Widget build(BuildContext context) {
    Person person = PersionShareDataWidget.of(context)!.data; //获取到上下文中的值
    return Text('${person.name.toString()}${person.age.toString()}');
  }
}

结尾

如果有不对或者需要补充的,欢迎在评论区留言