【Flutter学习】事件处理与通知之通知(Notification)

一,概述

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

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

NotificationListener(
  onNotification: (notification){
    //print(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属性,它记录了移动的位移,其它通知属性读者可以自己查看SDK文档。

二,自定义通知

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

  • 定义一个通知类,要继承自Notification类;
    class TestNotification extends Notification {
      TestNotification({
         @required this.count,
      });
      final int count;
    }
  • 子节点发送通知。
    new RaisedButton(
           textColor: Colors.black,
           child: new Center(
             child: new Text('点击传递随机数给上层Widget'),
           ),
           onPressed: () {
             new TestNotification(count: new Random().nextInt(100)).dispatch(key.currentContext);
           })
  • 父节点使用NotificationListener进行监听子节点发出的通知,并作出响应
    new NotificationListener(
               onNotification: (TestNotification n) {
                 scaffoldStateKey.currentState.showSnackBar(new SnackBar(content: new Text('随机数:${n.count}')));
                 return true;
               },
               child: new TestAPage(
                 key: key,
               ))

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

  • 示例
    下面我们看一个完整的例子:
    class NotificationRoute extends StatefulWidget {
      @override
      NotificationRouteState createState() {
        return new NotificationRouteState();
      }
    }
    
    class NotificationRouteState extends State<NotificationRoute> {
      String _msg="";
      @override
      Widget build(BuildContext context) {
        //监听通知  
        return NotificationListener<MyNotification>(
          onNotification: (notification) {
            setState(() {
              _msg+=notification.msg+"  ";
            });
          },
          child: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
    //          RaisedButton(
    //           onPressed: () => MyNotification("Hi").dispatch(context),
    //           child: Text("Send Notification"),
    //          ),  
                Builder(
                  builder: (context) {
                    return RaisedButton(
                      //按钮点击时分发通知  
                      onPressed: () => MyNotification("Hi").dispatch(context),
                      child: Text("Send Notification"),
                    );
                  },
                ),
                Text(_msg)
              ],
            ),
          ),
        );
      }
    }
    
    class MyNotification extends Notification {
      MyNotification(this.msg);
      final String msg;
    }

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

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

    运行效果如下:

猜你喜欢

转载自www.cnblogs.com/lxlx1798/p/11120759.html