20 | 关于跨组件传递数据,你只需要记住这三招
陈航
该思维导图由 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
《Flutter 核心技术与实战》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(23)
- 最新
- 精选
- Mr.J请你分别概括属性传值、InheritedWidget、Notification 与 EventBus 的优缺点。 ·属性传值:单页面同一个视图树中使用,或者通过构造方法将值传递过去,有点直接将值带过去,不需要过多的操作,缺点是多层级的Widget需要一层层的传值,效率很低;中间一层忘了传整个下游都中断,而且中间某一个层级修改了数据,上层无法及时更新; ·InheritedWidget:主要体现是下层Widget主动去向上层拿数据,实现相对复杂,(有个疑问,多层的视图树,在最下层直接使用of可以获取到最上层的数据吗?),缺点传值方向的单一; ·Notification:与InheritedWidget相反,主要体现推数据,针对性强,具体通知给哪个Widget明确,不需要跨多层实现,缺点实现起来相对繁琐点,传值方向单一; ·EventBus:订阅关系,针对性强,全局使用,缺点是不同的事件需要定义不同的实体,传递时要区分哪个事件传递给哪个控件,销毁Widget时不能忘记取消订阅;
作者回复: 赞 InheritedWidget 无论跨多少层都可以的
2019-08-14315 - 许童童老师能讲下闲鱼的Redux吗?
作者回复: 更推荐Provider
2019-08-13513 - 许童童请你分别概括属性传值、InheritedWidget、Notification 与 EventBus 的优缺点。 属性传值:简单,但跨多个父子节点不方便 InheritedWidget:跨多个父子节点方便,但修改数据麻烦 Notification :传递事件方便,读取不方便 EventBus :通过事件总线,全局,方便,但要记住事件名称,全局容易冲突,组件消除要清理事件。
作者回复: 赞
2019-08-138 - 淡~Bloc和scopedmodel等一些状态管理方案会讲吗,更富推荐那些做状态管理啊
作者回复: 推荐Provider
2019-08-142 - 寂寞不点烟subscription = eventBus.on().listen((event) { setState(() {msg+= event.msg;});//更新msg });event这样接收会出现事件混乱。应该加一层判断 if(event.runtimeType == CustomEvent){ setState(() { msg += event.msg; }); //更新msg }
作者回复: 赞
2019-12-171 - 🌝我通过子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
收起评论