【Flutter 專題】17 圖解 ListView 下拉刷新與上拉加載 (二)【NotificationListener】

      網友投稿 985 2025-03-31

      小菜上次嘗試 ListView 異步加載列表數據時,用了三方庫 flutter_refresh,這種方式使用很簡單。但列表數據的加載也絕非一種,小菜這次準備用原生嘗試一下。因為種種原因,小菜這次的整理距離上次時間很長,還是應該加強自控力。

      小菜這次的列表并沒有單獨處理動畫效果,只是對數據的刷新與加載更多進行正常加載進行處理,還需要進一步的學習研究。

      ListView + NotificationListener

      小菜參考了很多大神的實現方式,發現 NotificationListener 很像 Android 的滑動監聽事件,再頂部和底部添加事件處理,集成方式也很簡單。

      @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('新聞列表'), elevation: 0.0, // 陰影高度 ), body: new NotificationListener( onNotification: dataNotification, child: childWidget(), ), ); }

      【Flutter 專題】17 圖解 ListView 下拉刷新與上拉加載 (二)【NotificationListener】

      問題小結

      NotificationListener 中可以根據如下狀態進行判斷,并在相應的狀態下進行需要的處理:

      (notification.metrics.extentAfter == 0.0) 為滑動到 底部;

      (notification.metrics.extentBefore == 0.0) 為滑動到 頂部。

      bool dataNotification(ScrollNotification notification) { if (notification is ScrollEndNotification) { //下滑到最底部 if (notification.metrics.extentAfter == 0.0) { print('======下滑到最底部======'); loadData(); } //滑動到最頂部 if (notification.metrics.extentBefore == 0.0) { print('======滑動到最頂部======'); lastFileID = '0'; rowNumber = 0; dataItems.clear(); loadData(); } } return true; }

      小菜在測試過程中每次滑動一下列表都會調用一次接口,因為在監聽過程中若不做任何處理只要列表滑動便會進行監聽,小菜的解決的方式有兩種;

      監聽滑動到底部再進行業務操作調用接口,如問題一中的判斷;

      bool dataNotification(ScrollNotification notification) { if (notification is ScrollEndNotification) { //下滑到最底部 if (notification.metrics.extentAfter == 0.0) { print('======下滑到最底部======'); loadData(); } } return true; }

      嘗試使用 TrackingScrollController,對滑動進行監聽,這個類可用于同步兩個或更多個共享單個 TrackingScrollController 的惰性創建的滾動視圖的滾動偏移。它跟蹤最近更新的滾動位置,并將其報告為其初始滾動偏移量。且在非底部時 maxScrollExtent 和 offset 值會相等。使用該類監聽時更靈活,有些操作并非到底部才會進行處理等。

      bool dataNotification(ScrollNotification notification) { if (notification is ScrollUpdateNotification) { if (_scrollController.mostRecentlyUpdatedPosition.maxScrollExtent > _scrollController.offset && _scrollController.mostRecentlyUpdatedPosition.maxScrollExtent - _scrollController.offset <= 50) { loadData(); } } return true; }

      小菜以前對列表的處理只包括列表數據為 0 時展示 Loading 等待頁,有數據時展示數據列表,但是對于其他異常情況沒有處理,這次特意添加上異常頁面,這僅僅是業務方面的添加,沒有新的技術點。

      主要源碼

      class LoadMoreState extends State { var lastFileID = '0'; var rowNumber = 0; var cid = '29338'; var newsListBean = null; List dataItems = []; @override void initState() { super.initState(); loadData(); } // 請求首頁數據 Future loadData() { this.isLoading = true; final Completer completer = new Completer(); getNewsData(); completer.complete(null); return completer.future; } getNewsData() async { await http .get( 'https://XXX.....&lastFileID=${lastFileID}&rowNumber=${rowNumber}') .then((response) { if (response.statusCode == 200) { var jsonRes = json.decode(response.body); newsListBean = NewsListBean(jsonRes); setState(() { if (newsListBean != null && newsListBean.list != null && newsListBean.list.length > 0) { for (int i = 0; i < newsListBean.list.length; i++) { dataItems.add(newsListBean.list[i]); } lastFileID = newsListBean.list[newsListBean.list.length - 1].fileID.toString(); rowNumber += newsListBean.list.length; } else {} }); } }); } bool dataNotification(ScrollNotification notification) { if (notification is ScrollEndNotification) { //下滑到最底部 if (notification.metrics.extentAfter == 0.0) { print('======下滑到最底部======'); loadData(); } //滑動到最頂部 if (notification.metrics.extentBefore == 0.0) { print('======滑動到最頂部======'); lastFileID = '0'; rowNumber = 0; dataItems.clear(); loadData(); } } return true; } // 處理列表中是否有數據,對應展示相應頁面 Widget childWidget() { Widget childWidget; if (newsListBean != null && (newsListBean.success != null && !newsListBean.success)) { childWidget = new Stack( children: [ new Padding( padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 100.0), child: new Center( child: Image.asset( 'images/icon_wrong.jpg', width: 120.0, height: 120.0, ), ), ), new Padding( padding: new EdgeInsets.fromLTRB(0.0, 100.0, 0.0, 0.0), child: new Center( child: new Text( '抱歉!暫無內容哦~', style: new TextStyle(fontSize: 18.0, color: Colors.blue), ), ), ), ], ); } else if (dataItems != null && dataItems.length != 0) { childWidget = new Padding( padding: EdgeInsets.all(2.0), child: new ListView.builder( controller: _scrollController, physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.all(6.0), itemCount: dataItems == null ? 0 : dataItems.length, itemBuilder: (context, item) { return buildListData(context, dataItems[item]); }),); } else { childWidget = new Center( child: new Card( child: new Stack( children: [ new Padding( padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 35.0), child: new Center( child: SpinKitFadingCircle( color: Colors.blueAccent, size: 30.0, ), ), ), new Padding( padding: new EdgeInsets.fromLTRB(0.0, 35.0, 0.0, 0.0), child: new Center( child: new Text('正在加載中,莫著急哦~'), ), ), ])),); } return childWidget; } }

      小菜剛接觸 flutter 時間不長,還有很多不清楚和不理解的地方,如果又不對的地方還希望多多指出。

      來源:阿策小和尚

      Android Flutter ListView

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:okr軟件聯系方式(okR管理
      下一篇:excel表格怎樣快速填充公式
      相關文章
      亚洲av无码无线在线观看| 亚洲精品GV天堂无码男同| 国产AV日韩A∨亚洲AV电影| 亚洲一久久久久久久久| 亚洲国产91在线| 亚洲AV无码久久久久网站蜜桃 | www.亚洲精品| 亚洲不卡AV影片在线播放| 国产午夜亚洲精品不卡电影| 国产精品无码亚洲精品2021| 精品国产亚洲AV麻豆| 无码不卡亚洲成?人片| 无码不卡亚洲成?人片| 亚洲日韩国产精品乱| 亚洲中文字幕无码爆乳AV| 久久精品国产亚洲麻豆| 国产∨亚洲V天堂无码久久久| 国产亚洲人成无码网在线观看| 亚洲老妈激情一区二区三区| 亚洲av午夜福利精品一区人妖| 亚洲人成在线播放网站| 亚洲国产精品VA在线看黑人| 无码欧精品亚洲日韩一区| 久久亚洲私人国产精品| 亚洲大香人伊一本线| 亚洲videos| 亚洲爆乳少妇无码激情| 亚洲AV中文无码乱人伦| 国产亚洲精品自在线观看| 狠狠色伊人亚洲综合成人| 亚洲综合一区二区精品导航| 亚洲综合激情九月婷婷| 亚洲日本久久一区二区va| 亚洲欧美日韩中文字幕一区二区三区| 亚洲欧美精品午睡沙发| 亚洲成人影院在线观看| 亚洲日韩欧洲乱码AV夜夜摸| 亚洲第一成年男人的天堂| 亚洲国产成人久久| 亚洲第一成年免费网站| 亚洲国产综合精品一区在线播放|