内容简介:在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中消息传递》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Development Recipes
Brian P. Hogan、Chris Warren、Mike Weber、Chris Johnson、Aaron Godin / Pragmatic Bookshelf / 2012-1-22 / USD 35.00
You'll see a full spectrum of cutting-edge web development techniques, from UI and eye candy recipes to solutions for data analysis, testing, and web hosting. Make buttons and content stand out with s......一起来看看 《Web Development Recipes》 这本书的介绍吧!