内容简介:在native开发中消息传递有多种手段,系统的广播,第三方的eventbus等,在flutter中会有哪些手段呢?本篇将会介绍InheritedWidget和React中的context功能类似,和逐级传递数据相比,它们能实现组件跨级传递数据。InheritedWidget的在Widget树中数据传递方向是从上到下的,这和Notification的传递方向正好相反。
在native开发中消息传递有多种手段,系统的广播,第三方的eventbus等,在flutter中会有哪些手段呢?本篇将会介绍
Flutter中的消息传递
InheritedWidget
InheritedWidget是Flutter中非常重要的一个功能型Widget,它可以高效的将数据在
Widget树中向下传递、共享
,这在一些需要在Widget树中共享数据的场景中非常方便, 我们经常通过这样的方式,通过
BuildContext
,可以拿到
Theme
和
MediaQuery
InheritedWidget和React中的context功能类似,和逐级传递数据相比,它们能实现组件跨级传递数据。InheritedWidget的在Widget树中数据传递方向是从上到下的,这和Notification的传递方向正好相反。
在介绍StatefulWidget时,我们提到State对象有一个回调
didChangeDependencies
,它会在“依赖”发生变化时被Flutter Framework调用。而这个“依赖”指的就是是否使用了父widget中InheritedWidget的数据,如果使用了,则代表有依赖,如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的主题、locale等发生变化时有机会来做一些事情
比如
//得到状态栏的高度 var statusBarHeight = MediaQuery.of(context).padding.top; //复制合并出新的主题 var copyTheme =Theme.of(context).copyWith(primaryColor: Colors.blue); 复制代码
使用 InheritedWidget
主要涉及2部分工作量
- 创建一个继承自 InheritedWidget 的类,使用时将其插入 Widget 树
- 通过 BuildContext 对象提供的 inheritFromWidgetOfExactType 方法查找 Widget 树中最近的一个特定类型的 InheritedWidget 类的实例
共享数据类
class InheritedContext extends InheritedWidget { //数据 final InheritedTestModel inheritedTestModel; //点击+号的方法 final Function() increment; //点击-号的方法 final Function() reduce; InheritedContext({ Key key, @required this.inheritedTestModel, @required this.increment, @required this.reduce, @required Widget child, }) : super(key: key, child: child); static InheritedContext of(BuildContext context) { return context.inheritFromWidgetOfExactType(InheritedContext); } //是否重建widget就取决于数据是否相同 @override bool updateShouldNotify(InheritedContext oldWidget) { return inheritedTestModel != oldWidget.inheritedTestModel; } } 复制代码
在widget中使用共享数据
class CustomerWidgetB extends StatelessWidget { @override Widget build(BuildContext context) { final inheritedContext = InheritedContext.of(context); final inheritedTestModel = inheritedContext.inheritedTestModel; return new Padding( padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0), child: new Text( '当前count:${inheritedTestModel.count}', style: new TextStyle(fontSize: 20.0), ), ); } } 复制代码
在树中从上向下传递
@override Widget build(BuildContext context) { return new InheritedContext( inheritedTestModel: inheritedTestModel, increment: _incrementCount, reduce: _reduceCount, child: new Scaffold( appBar: new AppBar( title: new Text('InheritedWidgetTest'), ), body: new Column( children: <Widget>[ new Padding( padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0), child: new Text('我们常使用的\nTheme.of(context).textTheme\nMediaQuery.of(context).size等\n就是通过InheritedWidget实现的', style: new TextStyle(fontSize: 20.0),), ), new CustomerWidgetA(), new CustomerWidgetB(), new CustomerWidgetC(), ], ), )); } 复制代码
具体代码可以查看
常见错误
MediaQuery.of() called with a context that does not contain a MediaQuery
见ss stackoverflow.com/questions/5…
You need a
MaterialApp
or a WidgetsApp
arround your widget. They provide the MediaQuery
. When you call
.of(context)
Notification
notification 跟inheritedWidget恰恰相反,是从 子节点向父节点发送消息 在Widget树中,每一个节点都可以分发通知,通知会沿着当前节点(context)向上传递,所有父节点都可以通过NotificationListener来监听通知,Flutter中称这种通知由子向父的传递为“通知冒泡”(Notification Bubbling)。Flutter中很多地方使用了通知,如可滚动(Scrollable) Widget中滑动时就会分发ScrollNotification,而Scrollbar正是通过监听ScrollNotification来确定滚动条位置的。
使用Notification
- 自定义通知 要继承自Notification类
-
分发通知
Notification有一个
dispatch(context)
方法,它是用于分发通知的,我们说过context实际上就是操作Element的一个接口,它与Element树上的节点是对应的,通知会从context对应的Element节点向上冒泡。
class CustomerNotification extends Notification { CustomerNotification(this.msg); final String msg; } 复制代码
class NotificationStudyState extends State<NotificationStudy> { String _msg = ""; @override Widget build(BuildContext context) { //监听通知 return NotificationListener<CustomerNotification>( onNotification: (notification) { setState(() { _msg += notification.msg + " "; }); }, child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ // RaisedButton( // onPressed: () => CustomerNotification("Hello NotificationStudy").dispatch(context), // child: Text("Send Notification"), // ), Builder( builder: (context) { return RaisedButton( //按钮点击时分发通知 onPressed: () => CustomerNotification("Hello NotificationStudy").dispatch(context), child: Text("Send Notification"), ); }, ), Text(_msg) ], ), ), ); } } 复制代码
注意:代码中注释的部分是不能正常工作的,因为这个
context
是根Context,而NotificationListener是监听的子树,所以我们通过
Builder
来构建RaisedButton,来获得按钮位置的context。
以上代码 参见 github.com/xsfelvis/le…
事件总线
目前在已经有了一个eventbus插件
pub.flutter-io.cn/packages/ev…
用法跟原生eventbus类似
- 引入
import 'package:event_bus/event_bus.dart'; EventBus eventBus = new EventBus(); 复制代码
- 监听事件
eventBus.on().listen((event) { print(event.runtimeType); }); 复制代码
- 发送事件
eventBus.fire(event); 复制代码
以上所述就是小编给大家介绍的《Flutter中消息传递》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Runtime 学习:消息传递
- 微服务消息传递协议简介
- ASP.NET Core 消息传递:MediatR
- ASP.NET Core 消息传递:MediatR
- Objective-C runtime 消息传递与转发
- Deepstream 4.0 发布,数据同步和消息传递引擎
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript RIA开发实战
(英)Dennis Odell / 张立浩 / 清华大学出版社 / 2010 / 48.00元
本书介绍如何采用最合理的方式为RIA编写可靠的、易于维护的HTML、CSS和JavaScript代码,以及如何使用Ajax技术在后台实现浏览器与Web服务器的动态通信。本书将介绍您在构建Web应用程序时可能遇到的性能限制,以及如何以最佳的方式克服这些限制。此外,本书提供的提示可以使用户界面响应更加灵敏。 本书也将介绍如何通过添加使用自定义字体的印刷标题、多媒体回放组件、自定义窗体控件和动态绘......一起来看看 《JavaScript RIA开发实战》 这本书的介绍吧!