Flutter 核心技术与实战
陈航
前美团点评高级技术专家
42432 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 48 讲
Flutter 核心技术与实战
15
15
1.0x
00:00/00:00
登录|注册

20 | 关于跨组件传递数据,你只需要记住这三招

需要引入第三方插件
无需父子关系,适用于组件间不存在父子关系的数据传递
支持任意对象的传递
需要继承Notification类
适用于子Widget状态变更,发送通知上报的场景
从子Widget向上传递数据
仅提供数据读的能力,需要配合StatefulWidget的State进行数据修改
子Widget无需手动传递属性
高效地将数据在Widget树中进行跨层传递
对于深层组件传递冗余属性
适用于简单的数据传递
简单直接
缺点
优点
缺点
优点
缺点
优点
缺点
优点
EventBus
Notification
InheritedWidget
属性传值
跨组件数据传递

该思维导图由 AI 生成,仅供参考

你好,我是陈航。
在上一篇文章中,我带你一起学习了在 Flutter 中如何响应用户交互事件(手势)。手势处理在 Flutter 中分为两种:原始的指针事件处理和高级的手势识别。
其中,指针事件以冒泡机制分发,通过 Listener 完成监听;而手势识别则通过 Gesture 处理。但需要注意的是,虽然 Flutter 可以同时支持多个手势(包括一个 Widget 监听多个手势,或是多个 Widget 监听同一个手势),但最终只会有一个 Widget 的手势能够响应用户行为。为了改变这一点,我们需要自定义手势,修改手势竞技场对于多手势优先级判断的默认行为。
除了需要响应外部的事件之外,UI 框架的另一个重要任务是,处理好各个组件之间的数据同步关系。尤其对于 Flutter 这样大量依靠组合 Widget 的行为来实现用户界面的框架来说,如何确保数据的改变能够映射到最终的视觉效果上就显得更为重要。所以,在今天这篇文章中,我就与你介绍在 Flutter 中如何进行跨组件数据传递。
在之前的分享中,通过组合嵌套的方式,利用数据对基础 Widget 的样式进行视觉属性定制,我们已经实现了多种界面布局。所以,你应该已经体会到了,在 Flutter 中实现跨组件数据传递的标准方式是通过属性传值。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Flutter中跨组件数据传递有多种方案,包括InheritedWidget、Notification和EventBus。InheritedWidget可实现高效数据传递和读写操作,适用于子Widget跨层共享父Widget的属性。Notification机制则实现由下到上传递数据的跨层共享,通过监听子Widget事件实现界面刷新。而EventBus则无需父子关系,采用发布/订阅模式实现跨组件通信。通过示例演示了这三种方案的具体使用方法,为读者提供了清晰的技术指导。EventBus的使用方式灵活,支持任意对象的传递,且使用限制相对较少。总结了属性传值、InheritedWidget、Notification与EventBus的特点和使用场景,为读者提供了参考。文章还提供了GitHub上的示例代码供读者实际运行体验。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Flutter 核心技术与实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(23)

  • 最新
  • 精选
  • Mr.J
    请你分别概括属性传值、InheritedWidget、Notification 与 EventBus 的优缺点。 ·属性传值:单页面同一个视图树中使用,或者通过构造方法将值传递过去,有点直接将值带过去,不需要过多的操作,缺点是多层级的Widget需要一层层的传值,效率很低;中间一层忘了传整个下游都中断,而且中间某一个层级修改了数据,上层无法及时更新; ·InheritedWidget:主要体现是下层Widget主动去向上层拿数据,实现相对复杂,(有个疑问,多层的视图树,在最下层直接使用of可以获取到最上层的数据吗?),缺点传值方向的单一; ·Notification:与InheritedWidget相反,主要体现推数据,针对性强,具体通知给哪个Widget明确,不需要跨多层实现,缺点实现起来相对繁琐点,传值方向单一; ·EventBus:订阅关系,针对性强,全局使用,缺点是不同的事件需要定义不同的实体,传递时要区分哪个事件传递给哪个控件,销毁Widget时不能忘记取消订阅;

    作者回复: 赞 InheritedWidget 无论跨多少层都可以的

    2019-08-14
    3
    15
  • 许童童
    老师能讲下闲鱼的Redux吗?

    作者回复: 更推荐Provider

    2019-08-13
    5
    13
  • 许童童
    请你分别概括属性传值、InheritedWidget、Notification 与 EventBus 的优缺点。 属性传值:简单,但跨多个父子节点不方便 InheritedWidget:跨多个父子节点方便,但修改数据麻烦 Notification :传递事件方便,读取不方便 EventBus :通过事件总线,全局,方便,但要记住事件名称,全局容易冲突,组件消除要清理事件。

    作者回复: 赞

    2019-08-13
    8
  • 淡~
    Bloc和scopedmodel等一些状态管理方案会讲吗,更富推荐那些做状态管理啊

    作者回复: 推荐Provider

    2019-08-14
    2
  • 寂寞不点烟
    subscription = eventBus.on().listen((event) { setState(() {msg+= event.msg;});//更新msg });event这样接收会出现事件混乱。应该加一层判断 if(event.runtimeType == CustomEvent){ setState(() { msg += event.msg; }); //更新msg }

    作者回复: 赞

    2019-12-17
    1
  • 🌝
    我通过子widget类直接修改传入的父widget中的变量可以吗?实验过,如果是对象的变量可以直接修改掉。 class Obj { int a; String b; Obj({this.a, this.b}); } class OneWidget extends StatefulWidget { OneWidget({Key key}) : super(key: key); @override _OneWidgetState createState() => _OneWidgetState(); } class _OneWidgetState extends State<OneWidget> { Obj obj; @override Widget build(BuildContext context) { return TwoWidget(obj: obj); } } class TwoWidget extends StatefulWidget { final Obj obj; TwoWidget({Key key, this.obj}) : super(key: key); @override _TwoWidgetState createState() => _TwoWidgetState(); } class _TwoWidgetState extends State<TwoWidget> { @override Widget build(BuildContext context) { return FlatButton( onPressed: () { widget.obj.a = 123; }, child: Text('点击'), ); } }

    作者回复: 可以啊,对象是引用传递就没问题

    2019-11-13
  • 和小胖
    老师,dispose() { subscription.cancel();} 这里的 subscription 哪里来的呢?不是应该是 eventbus.destroy() 吗?

    作者回复: 注册通知(调用listen)的时候会返回一个监听对象,用于后续取消事件通知

    2019-09-10
  • 和小胖
    老师,上面提的问题似乎找到答案了。 把 _incrementCounter 传入到 CountContainer 里面或许是为了类似于 java 里面的多态,子类可以有很多,同时子类可以自定义很多自己的方法,但是在调用的时候都统一调用父类的同名方法。 而我用 state.increment 之所以不行,是因为我是 onPressed: () => state.increment 这样写的,如果改成 onPressed: () => state.increment() 其实也是可以的,或者按照老师那种 onPressed 的写法也是可以的。 onPressed: () => state.increment() 是否可以认为是在 onPressed 的回调响应里面调用了 state 的 increment() 方法而已,而 onPressed: state.increment 是不是可以看成是在拿 state 的 increment 属性在给 onPressed 这个属性赋值呢?

    作者回复: 赞,你已经得出正确结论了

    2019-09-10
  • 和小胖
    老师,请问下第一种父传子的方式,为啥要把 _incrementCounter 传入到CountContainer里面呢?在按钮的点击事件里面直接使用 state.model._incrementCounter() 不是也可以吗? 另外我发现我用state.model._incrementCounter()是可以,但是使用 state.increment 却无法让 数字变化,这是为什么呢?

    作者回复: 1.直接使用State当然可以呀,只是这个例子是演示如何通过InheritedWidget进行读写数据。InheritedWidget只能读不能写,要写数据得通过State中转一层 2.看评论你已经得出结论啦

    2019-09-10
  • 咖啡凉了
    class Counter extends StatelessWidget { @override Widget build(BuildContext context) { // 获取 InheritedWidget 节点 CountContainer state = CountContainer.of(context); return Scaffold( … body: Text( 'You have pushed the button this many times: ${state.model.count}', // 关联数据读方法 ), floatingActionButton: FloatingActionButton(onPressed: state.increment), // 关联数据修改方法 ); } } 我在尝试的时候遇到了问题,这段代码中的 state.increment ,没有反应,改成state.increment()才能响应。这是什么问题

    作者回复: 这段代码应该是没问题的,如果是用箭头函数才会有问题

    2019-09-09
收起评论
显示
设置
留言
23
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部