Search code examples
flutterdartgraphqlinfinite-scroll

flutter infinite scrolling data from server in listview builder


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,
                                                    ),
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ],
                                        ),
                                      )
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          ],
                        ),
                      ),
                    ),
                  );
                }));
      }
    }


Solution

  • 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