This is the third day of my participation in the November Gwen Challenge. Check out the details: the last Gwen Challenge 2021

Some time ago sorted out two kinds of ListView asynchronous load data, pull down refresh and slide up load more ways, each way has its own advantages, there are also a lot of big god on the net explained ListView data flow of various processing methods, small vegetables according to the actual situation sorted out try the third scheme.

RefreshIndicator Drop down refresh

The RefreshIndicator is one of the most widely used widgets on the Web. The RefreshIndicator provides a refresh callback port onRefresh. Just handle the data request in the callback interface as follows:

Future<Null> _loadRefresh() async {await future.delayed (Duration(seconds: 2), () { setState(() { dataItems.clear(); lastFileID = '0'; rowNumber = 0; _getNewsData(lastFileID, rowNumber); return null; }); }); _getNewsData(var lastID, var rowNum) async {await http. get('https://XXX... /getArticles? . &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 {} }); }}); } @override Widget build(BuildContext context) {return Scaffold(appBar: appBar (title: Text(" third loading mode "),), Body: new RefreshIndicator(Child: ListView.builder(itemCount: Items. length, itemBuilder: BuildListData (context, dataItems[index])), onRefresh: _loadRefresh, // refresh callback); }Copy the code

ScrollController slides to load more

Now that the list is refreshed, we can use the ScrollController to monitor whether the list is sliding to the bottom. There are two main steps:

  1. Add listening events during initialization to determine whether to slide to the bottom;
  2. Add a listener method to ListView.
ScrollController _scrollController = new ScrollController(); @override void initState() { super.initState(); _scrollController.addListener(() { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { _getMoreData(); }}); _getMoreData(); } @override Widget build(BuildContext context) {return Scaffold(appBar: appBar (title: Text(" third loading method "),), body: ListView.builder(itemCount: Items.length, itemBuilder: buildListData(context, dataItems[index]), controller: _scrollController, )); }Copy the code

At this point, the drop-down refresh and slide up loading of the list are basically complete; The next step is to combine the two, as follows:

Body: new Padding(Padding: EdgeInsets. All (2.0), Child: RefreshIndicator(onRefresh: _loadRefresh, child: ListView.builder( itemCount: dataItems.length, physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { return buildListData(context, dataItems[index]); }, controller: _scrollController, )));Copy the code

Tips: Pay attention to handling data interface request content.

Small optimization

Optimization 1: add animation effects
  1. Add a layout Widget to load more
  2. Add the number of items to itemCount by 1;
  3. Add listening judgment to display loading more to the layout Widget when sliding to the last item.
Body: new Padding(Padding: EdgeInsets. All (2.0), Child: RefreshIndicator(onRefresh: _loadRefresh, child: ListView.builder( itemCount: dataItems.length + 1, physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { if (index == dataItems.length) { return _buildProgressIndicator(); } else { return buildListData(context, dataItems[index]); } }, controller: _scrollController, ))); Widget _buildProgressIndicator() {return new Padding(Padding: Edgeinset.fromltrb (0.0, 14.0, 0.0, 14.0), child: new Opacity(Opacity: isShowLoading? 1.1:0.0, child: new Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ new SpinKitChasingDots(color: Colors.blueAccent, size: New Padding(Padding: edgeinset.fromltrb (10.0, 0.0, 0.0, 0.0), child: new Text(' loading...')],)); }Copy the code
Optimization 2: Add data when initializing the first loadloadinganimation

RefreshIndicator has a refresh animation, so the loading animation is only added when the data is loaded for the first time. The loading animation is only a small state judgment, including the failure page in abnormal cases as follows.

Widget childWidget() { Widget childWidget; if (newsListBean ! = null && (newsListBean.success ! = null && ! newsListBean.success)) { isFirstLoading = false; ChildWidget = new Stack(children: <Widget>[new Padding(Padding: new EdgeInsets. FromLTRB (0.0, 0.0, 0.0, 100.0), child: new Stack(children: <Widget>[new Padding: new EdgeInsets. FromLTRB (0.0, 0.0, 0.0, 100.0)) New Center(Child: image. asset('images/icon_wrong.jpg', width: 120.0, height: 120.0,))), new Padding(Padding: FromLTRB (0.0, 100.0, 0.0, 0.0), new EdgeInsets. FromLTRB (0.0, 100.0, 0.0, 0.0), child: new Center(child: new Text(' sorry! New TextStyle(fontSize: 18.0, color: color.blue),)))]; } else if (dataItems ! = null && dataItems.length ! = 0) { isFirstLoading = false; ChildWidget = new Padding(Padding: EdgeInsets. All (2.0), Child: RefreshIndicator(onRefresh: _loadRefresh, child: ListView.builder( itemCount: dataItems.length + 1, physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { if (index == dataItems.length) { return _buildProgressIndicator(); } else { return buildListData(context, dataItems[index]); } }, controller: _scrollController, ))); } else {if (isFirstLoading) {// Custom loading will only be displayed when loading data for the first time. ChildWidget = new Center(child: new Card(child: new Card) 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(' loading '),))),); } else {} } return childWidget; }Copy the code

Optimization 3: With helpFuture.delayed()Lazy loading is implemented to make data requests more cohesive.
_getMoreData() async {
  if (!isShowLoading) {
    setState(() {
      isShowLoading = true;
    });
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        _getNewsData(lastFileID, rowNumber);
        isShowLoading = false;
        return null;
      });
    });
  }
}
Copy the code

Xiao CAI has not been in touch with Flutter for a long time, and there are still many unclear and ununderstood aspects. I hope you can give me more advice if there is anything wrong.

Source: Little Monk A Ce