一、基本概念
- 在
widget
树中,每一个节点都可以分发通知
- 通知会沿着当前节点向上传递,所有父节点都可以通过
NotificationListener
来监听通知
Flutter
中将这种由子向父的传递通知的机制称为通知冒泡Notification Bubbling
- 通知冒泡和用户触摸事件冒泡是相似的,但有一点不同:通知冒泡可以中止,但用户触摸事件不行
二、系统通知
1、接收系统通知
例如:接收ListView
的通知
首先找到ListView
文档,ListView
提供了ScrollNotification
的通知类,同时有五个子类继承,分别是ScrollStartNotification
、ScrollUpdateNotification
、OverscrollNotification
、ScrollEndNotification
、UserScrollNotification
,
根据如下NotificationListener
的注释,可以直接对父类ScrollNotification
进行监听,也可以单独对某个通知子类型进行监听
1 2 3 4 5 6 7 8 9 10 11 12
| class NotificationListener<T extends Notification> extends StatelessWidget { const NotificationListener({ Key key, @required this.child, this.onNotification, }) : super(key: key);
... final Widget child; ... }
|
onNotification
回调为通知处理的回调,需要有返回值,如果有多层NotificationListener
监听,那么当返回值为true
时,阻止冒泡,其父级NotificationListener
将不再收到子级监听的通知类型,当返回值为false
时继续向上冒泡通知
代码如下
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) { if (onNotification != null && notification is T) { final bool result = onNotification(notification); return result == true; } return false; }
|
可以看到NotificationListener
的onNotification
回调最终是在_dispatch
方法中执行的,然后会根据返回值来确定是否继续向上冒泡,此处不再深究