【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。

    運行效果如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM