flutter infinite scrolling data from server in listview builder

Question

Asked by stysh on November 12, 2021 (source).

I am using graphql_flutter to load data from the server and I should update moreId for the update page in my server and get more data to load, and I need to use infinite for it.

How can I do it?

class MoreEpd extends StatefulWidget {
      final String moreId;
      const MoreEpd({Key? key, required this.moreId}) : super(key: key);
    
      @override
      _MoreEpdState createState() => _MoreEpdState();
    }
    
    class _MoreEpdState extends State<MoreEpd> {
      double pageWidth = 0;
      double pageHeigh = 0;
      int pageNum = 0;
    
      final String leftArrow = 'assets/icons/left-arrow.svg';
      String getSearchResult = """
     query homeview(\$moreId: ID!, \$page: Int! ){
        homeview(HM_ID: \$moreId, page: \$page){
        HM_ID
        HM_Type_ID
        HM_Type_Name
        HM_NAME
        Priority
        Details{
          HM_Det_ID
          HM_ID
          Ep_ID
          Pod_ID
          Link
          Image
          title
          Pod_title
          
        }
      }
    }
    """;
    
      @override
      Widget build(BuildContext context) {
        pageWidth = MediaQuery.of(context).size.width;
        pageHeigh = MediaQuery.of(context).size.height;
        return Container(
          child: Query(
            options: QueryOptions(
              document: gql(getSearchResult),
              variables: {'moreId': widget.moreId, 'page': pageNum},
            ),
            builder: (
              QueryResult result, {
              Refetch? refetch,
              FetchMore? fetchMore,
            }) {
              return handleResult(result);
            },
          ),
        );
      }
     Widget handleResult(QueryResult result) {
        var data = result.data!['homeview']['Details'] ?? [];
    
        return Container(
            child: ListView.builder(
                padding: EdgeInsets.only(top: 15),
                shrinkWrap: true,
                itemCount: data.length ,
                itemBuilder: (context, index) {
                  return InkWell(
                    onTap: () {},
                    child: Padding(
                      padding: EdgeInsets.only(
                          top: pageWidth * 0.0,
                          right: pageWidth * 0.08,
                          left: pageWidth * 0.08,
                          bottom: pageWidth * 0.0),
                      child: Container(
                        child: Stack(
                          children: [
                            Column(
                              children: [
                                Padding(
                                  padding:
                                      EdgeInsets.only(bottom: pageWidth * 0.060),
                                  child: Row(
                                    children: [
                                      Padding(
                                        padding:
                                            EdgeInsets.only(left: pageWidth * 0.01),
                                        child: Container(
                                          // alignment: Alignment.centerRight,
                                          width: pageWidth * 0.128,
                                          height: pageWidth * 0.128,
                                          decoration: BoxDecoration(
                                              image: DecorationImage(
                                                  fit: BoxFit.cover,
                                                  image: CachedNetworkImageProvider(
                                                    data[index]['Image'],
                                                  )),
                                              borderRadius: BorderRadius.all(
                                                  Radius.circular(15)),
                                              // color: Colors.redAccent,
                                              border: Border.all(
                                                color: MyColors.lightGrey,
                                                width: 1,
                                              )),
                                        ),
                                      ),
                                      Expanded(
                                        child: Row(
                                          children: [
                                            Column(
                                              crossAxisAlignment:
                                                  CrossAxisAlignment.start,
                                              children: [
                                                Container(
                                                  width: pageWidth * 0.5,
                                                  alignment: Alignment.centerRight,
                                                  child: Text(
                                                    data[index]['title'],
                                                    textAlign: TextAlign.right,
                                                    overflow: TextOverflow.ellipsis,
                                                    maxLines: 1,
                                                    // softWrap: true,
                                                    style: TextStyle(
                                                      // fontWeight: FontWeight.bold,
                                                      fontSize: 14,
                                                    ),
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ],
                                        ),
                                      )
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          ],
                        ),
                      ),
                    ),
                  );
                }));
      }
    }

Answer

Question answered by Yeasin S (source).

First error is happening because of not handling the states of Query. In order to do that on builder:

delearing data on state level var data = [];

     builder: (
                QueryResult result, {
                Refetch? refetch,
                FetchMore? fetchMore,
              }) {
                if (result.hasException) {
                  return Text(result.exception.toString());
                }
                if (result.isLoading) {
                  return Column(
                    children: [
                      Expanded(
                          child: handleResult(data)), // show data while loading
                      const Center(
                        child: CircularProgressIndicator(),
                      ),
                    ],
                  );
                }
                data.addAll(result.data!['homeview']['Details'] ?? []);
                return handleResult(data);
              },

All we need now to increase the pageNum to get more data. I'm using load more button, better will be creating the load button end of list by increasing itemLength+=1.

enter image description here

Update using ScrollController.

// on state class
  final ScrollController controller = ScrollController();
  bool isLoading = false;

Load data on scroll

  @override
  void initState() {
    super.initState();
    controller.addListener(() {
      /// load date at when scroll reached -100
      if (controller.position.pixels >
          controller.position.maxScrollExtent - 100) {
        print("Scroll on loading");
        if (!isLoading) {
          print("fetching");
          setState(() {
            pageNum++;
            isLoading = true;
          });
        }
      }
    });
  }

Full Snippet on Gist

And about the position issue, you can check this

DART FLUTTER GRAPHQL INFINITE-SCROLL
SHARE: