Flutter 组件通信
前言
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)
- 新建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});
}
- 使用
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()}');
}
}
5. 事件总线
- 封装一个事件总线的方法,新建bus.dart
//订阅者回调签名
typedef void EventCallback(arg);
class EventBus {
EventBus._internal();
//保存单例
static final EventBus _singleton = EventBus._internal();
//工厂构造函数
factory EventBus()=> _singleton;
//保存事件订阅者队列,key:事件名(id),value: 对应事件的订阅者队列
final _emap = <Object, List<EventCallback>?>{};
//添加订阅者
void on(eventName, EventCallback f) {
_emap[eventName] ??= <EventCallback>[];
_emap[eventName]!.add(f);
}
//移除订阅者
void off(eventName, [EventCallback? f]) {
var list = _emap[eventName];
if (eventName == null || list == null) return;
if (f == null) {
_emap[eventName] = null;
} else {
list.remove(f);
}
}
//触发事件,事件触发后该事件所有订阅者会被调用
void emit(eventName, [arg]) {
var list = _emap[eventName];
if (list == null) return;
int len = list.length - 1;
//反向遍历,防止订阅者在回调中移除自身带来的下标错位
for (var i = len; i > -1; --i) {
list[i](arg);
}
}
}
var bus = EventBus();
enum Event {
login,
}
- 使用
import 'bus.dart';
//....
class Father extends StatefulWidget {
const Father({super.key});
@override
State<Father> createState() => _FatherState();
}
class _FatherState extends State<Father> {
int count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const Text('父组件'),
ElevatedButton(
child: const Text("Increment"),
onPressed: () {
setState(() => ++count);
bus.emit(Event.login, count); //发布
},
),
const Child(),
],
),
);
}
}
class Child extends StatefulWidget {
const Child({super.key});
@override
State<Child> createState() => _ChildState();
}
class _ChildState extends State<Child> {
int count = 0;
void onChange(value) {
setState(() {
count = value;
});
}
@override
void initState() {
//订阅登录状态改变事件
bus.on(Event.login, onChange);
super.initState();
}
@override
void dispose() {
//取消订阅
bus.off(Event.login, onChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text('子组件$count');
}
}
结尾
如果有不对或者需要补充的,欢迎在评论区留言
转载自:https://juejin.cn/post/7185070762343006264