The listview and refreshindicator components are commonly used to implement pull-up loading and more drop-down refreshing of list pages

Time:2020-10-28

The most common app is the list page, pull up to load more, drop-down to refresh, in theFlutterinListView Is one of the most commonly used scrollable components, which I mainly use hereListViewRealize list loading, and cooperate withRefreshIndicatorComponent to achieve drop-down refresh; will also use the nested use of listview.

Creating stateful widgets

import 'dart:convert';
import 'package:app/common/httpUtil.dart';
import 'package:app/common/toast.dart';
import 'package:app/api/Api.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

class Questionnaire extends StatefulWidget {
  @override
  _QuestionnaireState createState() => _QuestionnaireState();
}

class _QuestionnaireState extends State<Questionnaire> {
  //The data to be displayed in the 'listview'.
  List questionnaireList = new List();

  ScrollController _scrollController = new ScrollController();

  bool isLoading = true;

  //Total pages
  int totalPages = 1;

  //Current number of pages
  int pageno = 0;  
  
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        Title: new text,
      ),
      body: Container(
         child: _buildList(),
      ),
      resizeToAvoidBottomPadding: false,
    );
  }
 }

Using DIO to get data

void _getMoreData() async {
    if (isLoading) {
      try {
       //Size number of data per page, start page 0, 1, 2
        String url = "/xxxx/xxxlist.json?size=10&start=" + pageno.toString();
        //Print ('interface pageno: '+ pageno.toString ());
        Response response = await dio.get(url);
        // print(response);

        setState(() {
          //Processing returned data
          //Total pages
          totalPages = response.data['totalPages'];
          // print(totalPages);
          questionnaireList.addAll(response.data['content']);
          // print(questionnaireList);
        });
      } on DioError catch (e) {
        //Catch prompt
        Print ('catch prompt: '+ e.tostring());
        if (e.response != null) {
          print(e.response.data);
          dynamic rtn = jsonDecode(e. response.data.toString ()); // parse the JSON data returned by the interface
          // print(rtn['status']);
          if (rtn['status'] == 401) {
            Autologin(). Then ((VAL) = > initstate()); // call initstate to update the page after automatic login
          }
        } else {
          Showtoast ("data load failed");
          print(e.request);
          print(e.message);
        }
      } finally {
        setState(() {
          isLoading = false;
        });
      }
    }
  }

The DIO used above ishttps://segmentfault.com/a/1190000021567794#item-2-1This article mentioned the creation of a global shared DIO.

Drop down refresh

Change it to “build indicator” in the middle layer,onRefreshTo retrieve the data.

    body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: _buildList(),
      ),
/*
   *Drop down refresh method 
   */
  Future<Null> _onRefresh() async {
    questionnaireList.clear();
    setState(() {
      isLoading = true;
    });
    _getMoreData();
  }

Pull up to load more

ListViewSupportscrollControllerEvent binding, when the user is inListViewWhen sliding, it will startscrollControllerevent.
scrollControllerComponents:scrollControllerIs a sliding listening component that we use to control when data is loaded.

stayscrollControllerAdd listening events inaddListenerTo determine whether to load more data when sliding a page, if it is not pulled to the bottom, and the data is not in the loading state, whether it is the last page, and other conditional logic is used to determine whether to load more data, and update the view through setstate.

@override
  void initState() {
    setState(() {
      isLoading = true;
    });
    this._getMoreData();
    super.initState();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        //Print ('slide to the bottom ');
        if (pageno < totalPages - 1) {
          pageno++;
          //Print ('load more pageno: '+ pageno.toString ());
          //Load more
          setState(() {
            isLoading = true;
          });
          _getMoreData();
        } else {
          //There is no more
          Showtoast ("no more");
        }
      }
    });
  }
  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

TheshowToastyesShowtoast, showloading, showconfirmdialogWritten inlib/common/toast.dartGlobal shared methods in.

Listview display

stayListView builderWe use conditional judgment to make the last line display no data, ProgressBar and data list.

  Widget _buildProgressIndicator() {
    return new Padding(
      padding: const EdgeInsets.all(8.0),
      child: new Center(
        child: new Opacity(
          opacity: isLoading ? 1.0 : 00,
          child: new CircularProgressIndicator(),
        ),
      ),
    );
  }
  
Widget _buildList() {
    return ListView.builder(
      //Itemcount + 1 is used to display the progressbar and no data in loading
      itemCount: questionnaireList.length + 1,
      itemBuilder: (context, index) {
        if (questionnaireList.length == 0 && isLoading) {
          //Loading
          return _buildProgressIndicator();
        } else if (questionnaireList.length == 0 && !isLoading) {
          //No data available
          return Padding(
            padding: const EdgeInsets.all(18.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                New text ('No data at present! )
              ],
            ),
          );
        } else if (questionnaireList.length == index && !isLoading) {
          //The extra 1 should not be displayed because there is no data. If this display is removed, an error will be reported
          return _buildProgressIndicator();
        } else {
          //List display
          return new GestureDetector(
            //Click tap event of list
            onTap: () => _handleTapToDetail(conductStatus),
            child: Card(
              child: _buildContainer(),
            ),
          );
        }
      },
      controller: _scrollController,
    );
  }
_handleTapToDetail(String conductStatus){
     //Click tap in the list to enter the logic of details or other operations
  }
  
  _buildContainer(){
    //The specific layout of the list content is omitted here
  }

The above describes how to use listview and refreshindicator components to implement pull-up loading and more drop-down refreshing of list pages.

Listview nesting listview scrolling problem

The above list is based on the questionnaire survey, so it is used hereListViewnestingListViewThe situation is the display of the list of questions in the questionnaire. We have done the questionnaire and test paper at ordinary times, and know that the list of topics includes: the topics of big questions, the topics of small questions, and the options of small questions. To do this layout, we use listview nesting.

The most important thing is the outermost layerListViewset upcontroller: _scrollControllerAnd set theshrinkWrap: trueAccording towidgetThe total length ofListViewThe length of. And then all nested insideChild listview, settingsshrinkWrap: trueAccording to the sonwidgetThe total length ofListViewAnd set thephysics: new NeverScrollableScrollPhysics()Disable scrolling events for issue list subcomponents.

new ListView(
          Shrinkwrap: true, // whether to set the length of listview according to the total length of child widgets. The default value is false
          controller: _scrollController,
          children: <Widget>[
                new Text(
                    "title",
                    overflow: TextOverflow.ellipsis,
                    maxLines: 2,
                    style: TextStyle(
                      color:  Color.fromRGBO (0, 0, 0, 1.0), // opacity: opacity
                      fontFamily: 'PingFangBold',
                      fontSize: 15.0,
                    ),
                  ),
                 Container(
                    child: _buildList(),
                  ),
          ],
        ),
Widget _buildList() {
    return ListView.builder(
      Shrinkwrap: true, // whether to set the length of listview according to the total length of child widgets. The default value is false
      // disable scrollphysics (), scrollphysics
      //Itemcount + 1 is used to display the progressbar in loading and no data at present
      itemCount: dataList.length + 1,
      itemBuilder: (context, index) {
          //The logic is similar to the above, not repeated, omitted
      },
    );
  }

reference material

ListView class: A scrollable list of widgets arranged linearly.
ListView

Drop down the filter to refresh and pull up to load more data
Filter listview paging load more effects
Summary of solving the problem of flutter: Scrollview nested listview scrolling problem
Fluent disable scrolling events

Recommended Today

Regular expression sharing for checking primes

This regular expression is shown as follows: Regular expressions for checking prime numbers or not To use this positive regular expression, you need to convert the natural number into multiple 1 strings. For example, 2 should be written as “11”, 3 should be written as “111”, 17 should be written as “11111111111”. This kind of […]