一、通知原理
1、通知(Notification)是Flutter中一个重要的机制,在widget树中,每一个节点都可以分发通知,通知会沿着当前节点向上传递,所有父节点都可以通过NotificationListener来监听通知。
2、Flutter中将这种由子向父的传递通知的机制称为通知冒泡(Notification Bubbling)。通知冒泡和用户触摸事件冒泡是相似的,但有一点不同:通知冒泡可以中止,但用户触摸事件不行。
3、通知冒泡和Web开发中浏览器事件冒泡原理是相似的,都是事件从出发源逐层向上传递,可以在上层节点任意位置来监听通知/事件,也可以终止冒泡过程,终止冒泡后,通知将不会再向上传递。
二、 监听通知
Flutter中很多地方使用了通知,如 Scrollable 组件,它在滑动时就会分发滚动通知(ScrollNotification),而 Scrollbar 正是通过监听 ScrollNotification 来确定滚动条位置的
下面是一个监听可滚动组件滚动通知的例子:
NotificationListener(
onNotification: (notification){
switch (notification.runtimeType){
case ScrollStartNotification: print("开始滚动"); break;
case ScrollUpdateNotification: print("正在滚动"); break;
case ScrollEndNotification: print("滚动停止"); break;
case OverscrollNotification: print("滚动到边界"); break;
}
},
child: ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(title: Text("$index"),);
}
),
);
上例中的滚动通知如ScrollStartNotification、ScrollUpdateNotification等都是继承自ScrollNotification类,不同类型的通知子类会包含不同的信息,比如ScrollUpdateNotification有一个scrollDelta属性,它记录了移动的位移
class NotificationListener<T extends Notification> extends StatelessWidget {
const NotificationListener({
Key key,
required this.child,
this.onNotification,
}) : super(key: key);
...//省略无关代码
}
可以看到:
NotificationListener继承自StatelessWidget类,所以它可以直接嵌套到 Widget 树中。NotificationListener可以指定一个模板参数,该模板参数类型必须是继承自Notification;当显式指定模板参数时,NotificationListener便只会接收该参数类型的通知。举个例子,如果我们将上例子代码改为:
//指定监听通知的类型为滚动结束通知(ScrollEndNotification)
NotificationListener<ScrollEndNotification>(
onNotification: (notification){
//只会在滚动结束时才会触发此回调
print(notification);
},
child: ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(title: Text("$index"),);
}
),
);
3、onNotification回调为通知处理回调,其函数签名如下:
typedef NotificationListenerCallback<T extends Notification> = bool Function(T notification);
它的返回值类型为布尔值,当返回值为true时,阻止冒泡,其父级Widget将再也收不到该通知;当返回值为false 时继续向上冒泡通知。