Flutter|常用数据通信组件

简介: 在做需求时经常会遇到组件间通信,本篇汇总了几种常用的通信方式

父子组件之间的通信
最简单的方式就是通过构造器传递数据,但当嵌套层级比较深的时,传参就比较难看了,或许这时还考虑用单例,但对于简单数据来说未免大材小用了。
例如,还是这个二级页场景,由多个子孙组件组成(同色框表示同级),在顶层页面可以知道从上个页面携带的数据,但最下层的输入框组件(箭头位置)也需要知道部分数据才能发送评论,这里说下如何用Provider快速实现。

Provider
介绍:基于InheritedWidget,一种自上向下的共享数据机制,方便子孙节点得到祖先节点共享的数据。
举例:

// 1、添加依赖
dependencies:
  provider: ^5.0.0

// 2、通过Provider包裹的child都共享数据 feedShareData
...
return Scaffold(
  ...
  body: Provider(
    create: (_) => feedShareData,
    child: Builder(builder: (context) {
   
      return FeedDetailPage();
    }),
  ),
);
// 3、在子孙组件都可以读取并修改共享数据
feedShareData = context.read<NormalFeedsDetailShareData>();
...

适用场景:当子组件需要共享祖先/父组件的数据时,尤其在跨层传递场景。
除了数据共享外,还有就是数据传递,也就是组件想知道另个组件的某些变化,并做出反应(callback)。在Dart中函数是可以当做对象传递的,但同样存在层级复杂时可能要传递大量的函数,接下来介绍常用的数据传递组件。

ChangeNotifier
介绍:可用于扩展Model,并在Model发生变化时调用notifyListeners使得监听该Model的组件重新构建。
举例:详见官方提供的案例,实现了加入购物车的效果。
适用场景: 常和Provider(Consumer)配套解决数据共享&状态传递问题。
NotificationListener
介绍:通知机制,即每个节点都可以向上发送Notification(自下向上的),除非中途被拦截否则会一直向上传。
举例:在上篇Flutter小白|初探事件处理介绍了如何通过NotificationListener解决多个滑动组件下、监听最外层组件滑动到边界事件,可见使用NotificationListener可以很方便获取到可滑动子组件的滑动行为。当然还可以在子组件上通过Notification#dispatch发送自定义通知,然后在上层接收并处理。

// 1、自定义通知类
class CustomNotification extends Notification {
   
  String msg;
  CustomNotification(this.msg);
}
// 2、子组件发送通知
...
CustomNotification("Test").dispatch(context);
...
// 3、父组件接收和处理通知
...
NotificationListener<CustomNotification>(
      onNotification: (notification) {
   
       // 处理逻辑
         // 同样的返回值表示是否拦截
       return true;
      },
      child:...
)

适用场景:当祖先/父组件要随着子组件的某些情况变化而变化时,常用于滑动情况。
兄弟组件之间的通信
ValueListenableBuilder
介绍:顾名思义,对某个 value进行监听,只要value发生变化就会直接通过setState重新构建子组件树。同样的,因为会rebuild,使用时尽可能缩小包裹的组件范围,以减少不必要的组件被重建、提高性能。
举例:例如想要实现这样的需求,底部输入框有内容时按钮亮起,无内容按钮置灰,代码如下:

// 1、创建:定义一个文本内容的ValueNotifier,
ValueNotifier<String> emojiInfoNotifier = ValueNotifier("");

// 2、使用:输入框组件和按钮组件都监听这个string信息
...
ValueListenableBuilder(
  valueListenable: emojiInfoNotifier,
  builder: (BuildContext context, String value, Widget? child) {
   
    // 输入框组件,根据输入内容展示,没有内容展示默认文案
    return Text(
      value.isEmpty
          ? Strings.share_thoughts
          : value,
      maxLines: 1,
      overflow: TextOverflow.ellipsis,
      style: TextStyle(fontSize: Res.t12, color: Res.c1),
    );
  },
),
...
ValueListenableBuilder(
  valueListenable: emojiInfoNotifier,
  builder: (BuildContext context, String value, Widget? child) {
   
    // 按钮组件,根据有无内容改变icon颜色
    return SvgPicture.asset(
      iconUrl,
      color: value.isEmpty ? Res.c4 : Res.c2,
      width: 16,
      height: 16,
    );
  },
),
...
// 3、随数据变化而变化:当点击表情按钮导致文本内容发生变化时,输入框组件和按钮组件都会发生变化,
...
GestureDetector(
  behavior: HitTestBehavior.opaque,
  onTap: () {
   
    // 超过最大表情展示个数会弹toast提示
    if (emojiInfoNotifier.value.characters.length >= maxInputEmojiCount) {
   
      Toasts.show(Strings.input_more);
    } else {
   
      emojiInfoNotifier.value += emoji?.text ?? "";
    }
  },
  child:... // 表情按钮
)...
// 4、销毁:在依赖组件dispose的同时销毁
@override
void dispose() {
   
  super.dispose();
  emojiInfoNotifier.dispose();
  ...
}

适用场景:当组件A要随着其他组件B上操作的数据变化而变化时,可以在同个组件树,也可以不是。常用于组件关系不复杂且监听数据简单的情况。
EventBus
介绍:对于要跨组件甚至跨页面组件通信的,这时用EventBus屡试不爽。关于 EventBus 开发一定非常熟悉了,核心就是观察者模式,一方发布消息,一方订阅感兴趣的消息并做处理。
举例:
// 1、添加依赖
dependencies:
event_bus: ^2.0.0

// 2、新增事件类
class CustomEvent {
String msg;
CustomEvent(this.msg);
}

// 3、发送事件(用单例维护,这里不展示了)
EventBusExt.getDefault().fire(CustomEvent("test"));

// 4、订阅事件并处理

EventBusExt.getDefault().on<CustomEvent>().listen((event) {
   
      // 处理逻辑
});

适用场景:可以在任何位置传递事件,可以解决大多数通信需求。
总结
本篇从数据通信方式(共享数据、传递数据)和组件关系(父子关系、兄弟关系)两方面分别介绍了Flutter中常用的组件,整体看Provider和EventBus总是能很好的处理各类场景,功能强大,但也有维护成本的问题(比如要新增很多事件类等),一些简单场景可以考虑其他小组件。

相关文章
|
3月前
|
传感器 缓存 监控
Stream 组件在 Flutter 中的应用场景有哪些?
Stream 组件在 Flutter 中的应用场景有哪些?
193 58
|
3月前
|
UED 开发者
Flutter|常用数据通信组件
Flutter|常用数据通信组件
114 49
|
1月前
Flutter 自定义组件继承与调用的高级使用方式
本文深入探讨了 Flutter 中自定义组件的高级使用方式,包括创建基本自定义组件、继承现有组件、使用 Mixins 和组合模式等。通过这些方法,您可以构建灵活、可重用且易于维护的 UI 组件,从而提升开发效率和代码质量。
136 1
|
1月前
|
开发工具 UED
Flutter&鸿蒙next中封装一个输入框组件
本文介绍了如何创建一个简单的Flutter播客应用。首先,通过`flutter create`命令创建项目;接着,在`lib`目录下封装一个自定义输入框组件`CustomInput`;然后,在主应用文件`main.dart`中使用该输入框组件,实现简单的UI布局和功能;最后,通过`flutter run`启动应用。本文还提供了后续扩展建议,如状态管理、网络请求和UI优化。
107 1
|
1月前
|
Dart UED
Flutter用户交互组件
Flutter用户交互组件
30 2
|
2月前
|
存储 开发框架 开发者
flutter:代码存储&基本组件 (五)
本文档介绍了Flutter中的一些基本组件和代码示例,包括代码存储、基本组件如AppBar的简单使用、可滑动切换的标签栏、TextField的多种用法(如简单使用、登录页面、文本控制器的监听与使用、修饰等),以及如何实现点击空白区域隐藏键盘等功能。通过这些示例,开发者可以快速掌握在Flutter应用中实现常见UI元素的方法。
|
1月前
|
开发工具
Flutter&鸿蒙next中封装一个列表组件
Flutter&鸿蒙next中封装一个列表组件
50 0
|
3月前
|
开发者
Flutter|常用数据通信组件
Flutter|常用数据通信组件
|
3月前
Stream 组件在 Flutter 中的具体使用方法是什么?
Stream 组件在 Flutter 中的具体使用方法是什么?
|
2月前
|
开发者
flutter:功能性组件 (八)
本文介绍了Flutter中常用的UI组件和功能,包括进度指示器(线性和圆形)、下拉刷新、选项按钮(单选按钮、复选框、开关)、手势识别(GestureDetector、Ink和InkWell)以及提示和Offstage组件的使用方法和示例代码。这些组件和功能可以帮助开发者快速构建交互丰富的应用程序界面。