Flutter通知Notification

本文最后更新于:2 年前

一、基本概念

  • widget树中,每一个节点都可以分发通知
  • 通知会沿着当前节点向上传递,所有父节点都可以通过NotificationListener来监听通知
  • Flutter中将这种由子向父的传递通知的机制称为通知冒泡Notification Bubbling
  • 通知冒泡和用户触摸事件冒泡是相似的,但有一点不同:通知冒泡可以中止,但用户触摸事件不行

二、系统通知

1、接收系统通知

例如:接收ListView的通知

  1. 首先找到ListView文档,ListView提供了ScrollNotification的通知类,同时有五个子类继承,分别是ScrollStartNotificationScrollUpdateNotificationOverscrollNotificationScrollEndNotificationUserScrollNotification

  2. 根据如下NotificationListener的注释,可以直接对父类ScrollNotification进行监听,也可以单独对某个通知子类型进行监听

1
2
3
4
5
6
7
8
9
10
11
12
class NotificationListener<T extends Notification> extends StatelessWidget {
/// Creates a widget that listens for notifications.
const NotificationListener({
Key key,
@required this.child,
this.onNotification,
}) : super(key: key);

...
final Widget child;
...
}
  1. onNotification回调为通知处理的回调,需要有返回值,如果有多层NotificationListener监听,那么当返回值为true时,阻止冒泡,其父级NotificationListener将不再收到子级监听的通知类型,当返回值为false时继续向上冒泡通知

  2. 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: NotificationListener<ScrollStartNotification>(
onNotification: (notification) {
print('父级监听开始滚动');
return true;
},
child: NotificationListener<ScrollStartNotification>(
onNotification: (notification) {
print('子级监听开始滚动');
return true;
},
child: ListView.builder(
itemBuilder: (context, index) {
return ListTile(
title: Text(index.toString()),
);
},
itemCount: 100,
),
),
),
);
}
}

2、自定义通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}

class _Page1State extends State<Page1> {
String _msg = "";

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('page1'),
),
body: NotificationListener<MyNotification>(
onNotification: (notification) {
setState(() {
_msg += notification.msg + " ";
});
return true;
},
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(_msg),
Builder(
builder: (context) {
return RaisedButton(
// 按钮点击时分发通知
onPressed: () {
MyNotification("Hi").dispatch(context);
},
child: Text("Send Notification"),
);
},
),
],
),
),
),
);
}
}

class MyNotification extends Notification {
MyNotification(this.msg);
final String msg;
}

  • 需要顶一个继承于Notification的通知类型
  • 使用NotificationListener对自定义的通知类型进行监听
  • 使用dispatch方法触发通知,此方法中的BuildContext参数必须是当前节点,不能使用超过NotificationListener的父节点

三、通知冒泡原理

1
2
3
4
5
6
7
8
9
10
bool _dispatch(Notification notification, Element element) {
// 如果通知监听器不为空,并且当前通知类型是该NotificationListener
// 监听的通知类型,则调用当前NotificationListener的onNotification
if (onNotification != null && notification is T) {
final bool result = onNotification(notification);
// 返回值决定是否继续向上遍历
return result == true;
}
return false;
}

可以看到NotificationListeneronNotification回调最终是在_dispatch方法中执行的,然后会根据返回值来确定是否继续向上冒泡,此处不再深究