Flutter中消息传递

首发于个人公众号javascript

Flutter中消息传递java

前言

在native开发中消息传递有多种手段,系统的广播,第三方的eventbus等,在flutter中会有哪些手段呢?本篇将会介绍git

Flutter中的消息传递

InheritedWidget

InheritedWidget是Flutter中很是重要的一个功能型Widget,它能够高效的将数据在Widget树中向下传递、共享,这在一些须要在Widget树中共享数据的场景中很是方便, 咱们常常经过这样的方式,经过BuildContext,能够拿到ThemeMediaQuerygithub

InheritedWidget和React中的context功能相似,和逐级传递数据相比,它们能实现组件跨级传递数据。InheritedWidget的在Widget树中数据传递方向是从上到下的,这和Notification的传递方向正好相反。app

在介绍StatefulWidget时,咱们提到State对象有一个回调didChangeDependencies,它会在“依赖”发生变化时被Flutter Framework调用。而这个“依赖”指的就是是否使用了父widget中InheritedWidget的数据,若是使用了,则表明有依赖,若是没有使用则表明没有依赖。这种机制可使子组件在所依赖的主题、locale等发生变化时有机会来作一些事情 好比less

//获得状态栏的高度
var statusBarHeight = MediaQuery.of(context).padding.top;
//复制合并出新的主题
var copyTheme =Theme.of(context).copyWith(primaryColor: Colors.blue);
复制代码

使用InheritedWidget

主要涉及2部分工做量ide

  • 建立一个继承自 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中使用共享数据ui

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),
      ),
    );
  }
}
复制代码

在树中从上向下传递this

@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);
复制代码
欢迎关注个人公众号,一块儿学习,共同提升~
复制代码

公众号小.jpg
相关文章
相关标签/搜索