Notification

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

Flutter中很多地方使用了通知,如可滚动(Scrollable) Widget中滑动时就会分发ScrollNotification,而Scrollbar正是通过监听ScrollNotification来确定滚动条位置的。除了ScrollNotification,Flutter中还有SizeChangedLayoutNotification、KeepAliveNotification 、LayoutChangedNotification等。下面是一个监听Scrollable Widget滚动通知的例子:

  1. NotificationListener(
  2. onNotification: (notification){
  3. //print(notification);
  4. switch (notification.runtimeType){
  5. case ScrollStartNotification: print("开始滚动"); break;
  6. case ScrollUpdateNotification: print("正在滚动"); break;
  7. case ScrollEndNotification: print("滚动停止"); break;
  8. case OverscrollNotification: print("滚动到边界"); break;
  9. }
  10. },
  11. child: ListView.builder(
  12. itemCount: 100,
  13. itemBuilder: (context, index) {
  14. return ListTile(title: Text("$index"),);
  15. }
  16. ),
  17. );

上例中的滚动通知如ScrollStartNotification、ScrollUpdateNotification等都是继承自ScrollNotification类,不同类型的通知子类会包含不同的信息,比如ScrollUpdateNotification有一个scrollDelta属性,它记录了移动的位移,其它通知属性读者可以自己查看SDK文档。

自定义通知

除了Flutter内部通知,我们也可以自定义通知,下面我们看看如何实现自定义通知:

  1. 定义一个通知类,要继承自Notification类;

    1. class MyNotification extends Notification {
    2. MyNotification(this.msg);
    3. final String msg;
    4. }
  2. 分发通知。

    Notification有一个dispatch(context)方法,它是用于分发通知的,我们说过context实际上就是操作Element的一个接口,它与Element树上的节点是对应的,通知会从context对应的Element节点向上冒泡。

下面我们看一个完整的例子:

  1. class NotificationRoute extends StatefulWidget {
  2. @override
  3. NotificationRouteState createState() {
  4. return new NotificationRouteState();
  5. }
  6. }
  7. class NotificationRouteState extends State<NotificationRoute> {
  8. String _msg="";
  9. @override
  10. Widget build(BuildContext context) {
  11. //监听通知
  12. return NotificationListener<MyNotification>(
  13. onNotification: (notification) {
  14. setState(() {
  15. _msg+=notification.msg+" ";
  16. });
  17. },
  18. child: Center(
  19. child: Column(
  20. mainAxisSize: MainAxisSize.min,
  21. children: <Widget>[
  22. // RaisedButton(
  23. // onPressed: () => MyNotification("Hi").dispatch(context),
  24. // child: Text("Send Notification"),
  25. // ),
  26. Builder(
  27. builder: (context) {
  28. return RaisedButton(
  29. //按钮点击时分发通知
  30. onPressed: () => MyNotification("Hi").dispatch(context),
  31. child: Text("Send Notification"),
  32. );
  33. },
  34. ),
  35. Text(_msg)
  36. ],
  37. ),
  38. ),
  39. );
  40. }
  41. }
  42. class MyNotification extends Notification {
  43. MyNotification(this.msg);
  44. final String msg;
  45. }

上面代码中,我们每点一次按钮就会分发一个MyNotification类型的通知,我们在Widget根上监听通知,收到通知后我们将通知通过Text显示在屏幕上。

注意:代码中注释的部分是不能正常工作的,因为这个context是根Context,而NotificationListener是监听的子树,所以我们通过Builder来构建RaisedButton,来获得按钮位置的context。

运行效果如下:

Screenshot_1539328127