今天来聊聊Flutter页面传值的几种方式:

  • InheritWidget
  • Notification
  • Eventbus

InheritWidget

如果看过Provider的源码的同学都知道,Provider跨组件传值的原理就是根据系统提供的InheritWidget实现的,让我们来看一下这个组件。
InheritWidget是一个抽象类,我们写一个保存用户信息的类UserInfoInheritWidget继承于InheritWidget:

 class UserInfoInheritWidget extends InheritedWidget { UserInfoBean userInfoBean; UserInfoInheritWidget({Key key, this.userInfoBean, Widget child}) : super (child: child); static UserInfoWidget of(BuildContext context){ return context.dependOnInheritedWidgetOfExactType<UserInfoWidget>(); } @override bool updateShouldNotify(UserInfoInheritWidget oldWidget) { return oldWidget.userInfoBean != userInfoBean; } } 

 class UserInfoBean { String name; String address; UserInfoBean({this.name, this.address}); } 

 class Page19PassByValue extends StatefulWidget { @override _Page19PassByValueState createState() => _Page19PassByValueState(); } class _Page19PassByValueState extends State<Page19PassByValue> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('PassByValue'), ), body: DefaultTextStyle( style: TextStyle(fontSize: 30, color: Colors.black), child: Column( children: [ Text(UserInfoWidget.of(context)!.userInfoBean.name), Text(UserInfoWidget.of(context)!.userInfoBean.address), SizedBox(height: 40), TextButton( child: Text('点击跳转'), onPressed: (){ Navigator.of(context).push(CupertinoPageRoute(builder: (context){ return DetailPage(); })); }, ) ], ), ), ); } } 

 class DetailPage extends StatefulWidget { @override _DetailPageState createState() => _DetailPageState(); } class _DetailPageState extends State<DetailPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Detail'), ), body: DefaultTextStyle( style: TextStyle(fontSize: 30, color: Colors.black), child: Center( child: Column( children: [ Text(UserInfoWidget.of(context).userInfoBean.name), Text(UserInfoWidget.of(context).userInfoBean.address), TextButton( onPressed: () { setState(() { UserInfoWidget.of(context)!.updateBean('wf123','address123'); }); }, child: Text('点击修改')) ], ), ), ) ); } } 

 class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return UserInfoWidget( userInfoBean: UserInfoBean(name: 'wf', address: 'address'), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ), ); } } 

 class _UserInfoInheritWidget extends InheritedWidget { UserInfoBean userInfoBean; Function update; _UserInfoInheritWidget({Key key, this.userInfoBean, this.update, Widget child}) : super (child: child); updateBean(String name, String address){ update(name, address); } @override bool updateShouldNotify(_UserInfoInheritWidget oldWidget) { return oldWidget.userInfoBean != userInfoBean; } } class UserInfoWidget extends StatefulWidget { UserInfoBean userInfoBean; Widget child; UserInfoWidget({Key key, this.userInfoBean, this.child}) : super (key: key); static _UserInfoInheritWidget of(BuildContext context){ return context.dependOnInheritedWidgetOfExactType<_UserInfoInheritWidget>(); } @override State<StatefulWidget> createState() => _UserInfoState(); } class _UserInfoState extends State <UserInfoWidget> { _update(String name, String address){ UserInfoBean bean = UserInfoBean(name: name, address: address); widget.userInfoBean = bean; setState(() {}); } @override Widget build(BuildContext context) { return _UserInfoInheritWidget( child: widget.child, userInfoBean: widget.userInfoBean, update: _update, ); } } 

上面把继承自InheritWidget的类改了一个名字:_UserInfoInheritWidget,对外只暴露用StatefulWidget封装过的UserInfoWidget,向_UserInfoInheritWidget传入了包含setState的更新数据方法,更新数据的时候通过UserInfoWidget.of(context)获取到继承于InheritWidget的_UserInfoInheritWidget类,调用updateBean方法实际上就调用了包含setState的方法,所以做到了数据更新和页面刷新

 T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect }); 

了解Widget、Element、RenderObject三只之间关系的同学都知道,其实context是Element的一个实例,BuildContext的注释也提到了这一点:

 @override T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) { assert(_debugCheckStateIsActiveForAncestorLookup()); final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T]; if (ancestor != null) { assert(ancestor is InheritedElement); return dependOnInheritedElement(ancestor, aspect: aspect) as T; } _hadUnsatisfiedDependencies = true; return null; } 

 void _updateInheritance() { assert(_lifecycleState == _ElementLifecycle.active); _inheritedWidgets = _parent?._inheritedWidgets; } 

 @mustCallSuper void mount(Element? parent, dynamic newSlot) { ... ...省略无关代码 _parent = parent; _slot = newSlot; _lifecycleState = _ElementLifecycle.active; _depth = _parent != null ? _parent!.depth + 1 : 1; if (parent != null) // Only assign ownership if the parent is non-null _owner = parent.owner; final Key? key = widget.key; if (key is GlobalKey) { key._register(this); } _updateInheritance();//这里调用了一次 } 

 @mustCallSuper void activate() { ... ...已省略无关代码 final bool hadDependencies = (_dependencies != null && _dependencies!.isNotEmpty) || _hadUnsatisfiedDependencies; _lifecycleState = _ElementLifecycle.active; _dependencies?.clear(); _hadUnsatisfiedDependencies = false; _updateInheritance();//这里又调用了一次 if (_dirty) owner!.scheduleBuildFor(this); if (hadDependencies) didChangeDependencies(); } 

Notification

 class Page19PassByValue extends StatefulWidget { @override _Page19PassByValueState createState() => _Page19PassByValueState(); } class _Page19PassByValueState extends State<Page19PassByValue> { UserInfoBean userInfoBean = UserInfoBean(name: 'wf', address: 'address'); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('PassByValue'), ), body: Center( child: NotificationListener<MyNotification>( onNotification: (MyNotification data) { userInfoBean = data.userInfoBean; setState(() {}); ///这里需要返回一个bool值,true表示阻止事件继续向上传递,false表示事件可以继续向上传递到父级组件 return true; }, child: Builder( ///这里用了一个Builder包装了一下,为的是能取到 ///NotificationListener的context builder: (context) { return Column( children: [ Text(userInfoBean.name), Text(userInfoBean.address), Container( child: FlatButton( child: Text('点击传值'), onPressed: () { MyNotification(userInfoBean: UserInfoBean(name: 'wf123', address: 'address123')).dispatch(context); }, ), ) ], ); }, ), ), ), ); } }

 ///Notification是一个抽象类, ///使用Notification需要自定义一个class继承Notification class MyNotification extends Notification { UserInfoBean userInfoBean; MyNotification({this.userInfoBean}) : super(); } 

 void dispatch(BuildContext target) { // The `target` may be null if the subtree the notification is supposed to be // dispatched in is in the process of being disposed. target?.visitAncestorElements(visitAncestor); }

 @protected @mustCallSuper bool visitAncestor(Element element) { if (element is StatelessElement) { final StatelessWidget widget = element.widget; if (widget is NotificationListener<Notification>) { if (widget._dispatch(this, element)) // that function checks the type dynamically return false; } } return true; } 

 @override void visitAncestorElements(bool visitor(Element element)) { assert(_debugCheckStateIsActiveForAncestorLookup()); Element? ancestor = _parent; while (ancestor != null && visitor(ancestor)) ancestor = ancestor._parent; } 

 final NotificationListenerCallback<T>? onNotification; bool _dispatch(Notification notification, Element element) { if (onNotification != null && notification is T) { final bool result = onNotification!(notification); return result == true; // so that null and false have the same effect } return false; } 

Eventbus

Eventbus用于两个不同的页面,可以跨多级页面传值,用法也比较简单,我创建了一个EventBusUtil来创建一个单例
import 'package:event_bus/event_bus.dart';

 class EventBusUtil { static EventBus ? _instance; static EventBus getInstance(){ if (_instance == null) { _instance = EventBus(); } return _instance!; } } 

 class Page19PassByValue extends StatefulWidget { @override _Page19PassByValueState createState() => _Page19PassByValueState(); } class _Page19PassByValueState extends State<Page19PassByValue> { UserInfoBean userInfoBean = UserInfoBean(name: 'wf', address: 'address'); @override void initState() { super.initState(); EventBusUtil.getInstance().on<UserInfoBean>().listen((event) { setState(() { userInfoBean = event; }); }); } @override void dispose() { super.dispose(); //不用的时候记得关闭 EventBusUtil.getInstance().destroy(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('PassByValue'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(userInfoBean.name), Text(userInfoBean.address), TextButton(onPressed: (){ Navigator.of(context).push(CupertinoPageRoute(builder: (_){ return EventBusDetailPage(); })); }, child: Text('点击跳转')) ], ), ), ); } } 

 class EventBusDetailPage extends StatefulWidget { @override _EventBusDetailPageState createState() => _EventBusDetailPageState(); } class _EventBusDetailPageState extends State<EventBusDetailPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('EventBusDetail'), ), body: Center( child: TextButton(onPressed: (){ EventBusUtil.getInstance().fire(UserInfoBean(name: 'name EventBus', address: 'address EventBus')); }, child: Text('点击传值')), ), ); } } 

 class Page19PassByValue extends StatefulWidget { @override _Page19PassByValueState createState() => _Page19PassByValueState(); } StreamController controller = StreamController(); class _Page19PassByValueState extends State<Page19PassByValue> { //设置一个初始值 UserInfoBean userInfoBean = UserInfoBean(name: 'wf', address: 'address'); @override void initState() { super.initState(); controller.stream.listen((event) { setState(() { userInfoBean = event; }); }); } @override void dispose() { super.dispose(); //页面销毁的时候记得关闭 controller.close(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('PassByValue'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(userInfoBean.name), Text(userInfoBean.address), TextButton(onPressed: (){ Navigator.of(context).push(CupertinoPageRoute(builder: (_){ return MyStreamControllerDetail(); })); }, child: Text('点击跳转')) ], ), ) ); } }

 class MyStreamControllerDetail extends StatefulWidget { @override State<StatefulWidget> createState() { return _MyStreamControllerDetailState(); } } class _MyStreamControllerDetailState extends State <MyStreamControllerDetail> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('StreamController'), ), body: Center( child: TextButton(onPressed: (){ //返回上个页面,会发现页面的数据已经变了 controller.sink.add(UserInfoBean(name: 'StreamController pass name: 123', address: 'StreamController pass address 123')); }, child: Text('点击传值'),), ), ); } }

到此这篇关于Flutter页面传值的几种方式的文章就介绍到这了,更多相关Flutter页面传值内容请搜索本网站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本网站!

您可能感兴趣的文章:

  • Flutter路由跳转参数处理技巧详解
  • flutter 路由跳转的实现示例
  • Flutter 使用Navigator进行局部跳转页面的方法
  • Flutter路由的跳转、动画和传参详解(最简单)
  • Flutter 页面跳转和传值的实现