Flutter 17: 圖解 ListView 下拉重新整理與上拉載入 (一)
小菜上次學 ListView 時,只學習了一下非同步請求資料載入新聞和 Loading 等待的小知識點,但對於新聞列表資料的更新和載入更多是必不可少的,而實現【下拉重新整理】與【上劃載入更多】的方式有很多種,今天小菜整理一下使用三方庫 ofollow,noindex">flutter_refresh 來實現列表的資料更新。
小菜也是再偶然間看到有大神用到這個三方庫的,小菜想要嘗試的原因主要是因為一是因為 flutter_refresh 整合很簡單,不用單獨寫頭部樣式和底部載入時的 loading 等;二是小菜技術太有限,對 Flutter 的未知有太多,想多嘗試幾種方式。

整合方式
- pubspec.yaml 中 新增 flutter_refresh : ^0.0.2 ,並同步 packages get ;
- 在相應的 .dart 檔案中新增引用 import 'package:flutter_refresh/flutter_refresh.dart';
- 資料載入時暫時不用 ListView 變更為 new Refresh ,小菜主要是處理 onHeaderRefresh 下拉重新整理 和 onFooterRefresh 底部重新整理 兩個方法中的資料處理。小菜的測試介面需要根據每一頁的最後一個新聞ID 和 整個的新聞數量為引數值進行處理。

// 頂部重新整理 Future<Null> onHeaderRefresh() { return new Future.delayed(new Duration(seconds: 2), () { setState(() { rowNumber = 0; lastFileID = '0'; newsListBean = null; getNewsData(lastFileID, rowNumber); }); }); } // 底部重新整理 Future<Null> onFooterRefresh() async { return new Future.delayed(new Duration(seconds: 2), () { setState(() { getNewsData(lastFileID, rowNumber); }); }); } // 介面資料處理 getNewsData(var lastID, var rowNum) async { await http .get( 'https://...?lastFileID=${lastID}&rowNumber=${rowNum}') .then((response) { if (response.statusCode == 200) { var jsonRes = json.decode(response.body); newsListBean = NewsListBean(jsonRes); if (lastID == '0' && rowNum==0 && dataItems != null) { dataItems.clear(); } 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 {} }); } }); } Widget childFreshWidget() { Widget childFreWi; if (dataItems != null && dataItems.length != 0) { childFreWi = new Padding( padding: EdgeInsets.all(6.0), child: new Refresh( onFooterRefresh: onFooterRefresh, onHeaderRefresh: onHeaderRefresh, childBuilder: (BuildContext context, {ScrollController controller, ScrollPhysics physics}) { return new Container( child: new ListView.builder( physics: physics, controller: controller, itemCount: rowNumber, itemBuilder: (context, item) { return buildListData(context, dataItems[item]); }, )); }, ), ); } else { childFreWi = new Stack( children: <Widget>[ 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 childFreWi; }

下拉重新整理

上拉載入更多
問題小結
小菜在測試過程中遇到了很多的小問題,現在逐一整理一下。
問題一:初始化進入頁面後,載入完第一頁之後重新整理資料不載入,第二次重新整理資料才載入,且載入的是上一次重新整理的資料?
解決方式:
- 進入頁面時呼叫資料介面 initState() ,為了保證第一次正常載入;
- 在 getNewsData() 中一定一定要新增 setState(() {}); 小菜在測試時,每次重新整理介面都會正常呼叫,但是都是第二次重新整理才載入第一次重新整理的資料,介面是正常的,但是資料總是慢一拍,小菜測試發現因為沒有用 setState(() {}); 以後一定要注意,這樣才可以實時進行更新。
問題二:下拉重新整理過程中,介面資料重複載入?
解決方式:
小菜目前還沒有涉及快取等方面的,單純的一個下拉重新整理應該是重新呼叫初始的介面,首先要清空列表,不然介面資料重複實實在在會出現的。
Future<Null> onHeaderRefresh() { return new Future.delayed(new Duration(seconds: 2), () { setState(() { rowNumber = 0; lastFileID = '0'; if (dataItems != null) { dataItems.clear(); } getNewsData(lastFileID, rowNumber); }); }); }
問題三:根據問題二的解決方案,顯示正常,但是執行時 Log 報錯,提示 Widget 已建立?

解決方案:
小菜測試了很久,把這個判斷列表制空從 onHeaderRefresh() 中移到資料處理的 getNewsData() 方法中,雖然不是非常理解,但是問題可以正常解決,小菜的理解是 onHeaderRefresh() 中處理的是資料和 Widget,而小菜自己的方法中是單純的資料處理。
if (lastID == '0' && rowNum==0 && dataItems != null) { dataItems.clear(); }
小菜剛接觸 Flutter 時間不長,還有很多不清楚和不理解的地方,如果又不對的地方還希望多多指出。以下是小菜公眾號,歡迎閒來吐槽~

公眾號