Flutter-監(jiān)聽滾動事件

對于滾動的視圖,我們經常需要監(jiān)聽它的一些滾動事件,在監(jiān)聽到的時候去做對應的一些事情。
比如視圖滾動到底部時,我們可能希望做上拉加載更多;
比如滾動到一定位置時顯示一個回到頂部的按鈕,點擊回到頂部的按鈕,回到頂部;
比如監(jiān)聽滾動什么時候開始,什么時候結束;
在Flutter中監(jiān)聽滾動相關的內容由兩部分組成:ScrollController和ScrollNotification。

1. ScrollController

在Flutter中,Widget并不是最終渲染到屏幕上的元素(真正渲染的是RenderObject),因此通常這種監(jiān)聽事件以及相關的信息并不能直接從Widget中獲取,而是必須通過對應的Widget的Controller來實現(xiàn)。

ListView、GridView的組件控制器是ScrollController,我們可以通過它來獲取視圖的滾動信息,并且可以調用里面的方法來更新視圖的滾動位置。

另外,通常情況下,我們會根據(jù)滾動的位置來改變一些Widget的狀態(tài)信息,所以ScrollController通常會和StatefulWidget一起來使用,并且會在其中控制它的初始化、監(jiān)聽、銷毀等事件。

我們來做一個案例,當滾動到1000位置的時候,顯示一個回到頂部的按鈕:

  • jumpTo(double offset)、animateTo(double offset,...):這兩個方法用于跳轉到指定的位置,它們不同之處在于,后者在跳轉時會執(zhí)行一個動畫,而前者不會。
  • ScrollController間接繼承自Listenable,我們可以根據(jù)ScrollController來監(jiān)聽滾動事件。
class MyHomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyHomePageState();
  }
}

class _MyHomePageState extends State<MyHomePage> {

  ScrollController _controller;
  bool _isShowTop = false;

  @override
  void initState() {
    //初始化ScrollController
    _controller = ScrollController();

    //監(jiān)聽滾動
    _controller.addListener((){
      var tempShowTop = _controller.offset >= 1000;
      if(tempShowTop != _isShowTop){
        setState(() {
          _isShowTop = tempShowTop;
        });
      }
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ListView展示"),
      ),
      body: ListView.builder(
        itemCount: 100,
        itemExtent: 60,
        controller: _controller,
        itemBuilder: (BuildContext context,int index){
          return ListTile(
            title: Text("item $index"),
          );
        },
      ),
      floatingActionButton: !_isShowTop?null:FloatingActionButton(
        child: Icon(Icons.arrow_upward),
        onPressed: (){
          _controller.animateTo(0, duration: Duration(milliseconds: 1000), curve: Curves.ease);
        },
      ),
    );
  }
}
image.png

2. NotificationListener

如果我們希望監(jiān)聽什么時候開始滾動,什么時候結束滾動,這個時候我們可以通過NotificationListener。

  • NotificationListener是一個Widget,模板參數(shù)T是想監(jiān)聽的通知類型,如果省略,則所有類型通知都會被監(jiān)聽,如果指定特定類型,則只有該類型的通知會被監(jiān)聽。
  • NotificationListener需要一個onNotification回調函數(shù),用于實現(xiàn)監(jiān)聽處理邏輯。
  • 該回調可以返回一個布爾值,代表是否阻止該事件繼續(xù)向上冒泡,如果為true時,則冒泡終止,事件停止向上傳播,如果不返回或者返回值為false 時,則冒泡繼續(xù)。

案例: 列表滾動, 并且在中間顯示滾動進度

class MyHomeNotificationDemo extends StatefulWidget {
  @override
  _MyHomeNotificationDemoState createState() => _MyHomeNotificationDemoState();
}

class _MyHomeNotificationDemoState extends State<MyHomeNotificationDemo> {

  int _progress = 0;

  @override
  Widget build(BuildContext context) {
    return NotificationListener(
      onNotification: (ScrollNotification notification){
        //1.監(jiān)聽事件的類型
        if(notification is ScrollStartNotification){
          print("開始滾動...");
        }else if(notification is ScrollUpdateNotification){
          //當前滾動的位置和總長度
          final currentPixel = notification.metrics.pixels;
          final totalPixel = notification.metrics.maxScrollExtent;
          double progress = currentPixel/totalPixel;
          setState(() {
            _progress = (progress*100).toInt();
          });
          print("正在滾動:${notification.metrics.pixels} - ${notification.metrics.maxScrollExtent}");
        }else if(notification is ScrollEndNotification){
          print("滾動結束....");
        }
        return false;
      },
      child: Stack(
        alignment: Alignment(.9,.9),
        children: <Widget>[
          ListView.builder(
            itemCount: 100,
            itemExtent: 80,
            itemBuilder: (BuildContext context,int index){
              return ListTile(title: Text("item $index"),);
            },
          ),
          CircleAvatar(
            radius: 30,
            child: Text("$_progress%"),
            backgroundColor: Colors.black54,
          ),
        ],
      ),
    );
  }
}
image.png

學習內容來自Flutter從入門到實戰(zhàn)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容