flutterpaginationinfinite-scroll

Flutter Infinite Scroll Pagination page listener is fetching next page automatically and not when the screen is scrolled


In this example, I am trying to use the infinite_scroll_pagination package from pub.dev to build a PagedGridView. Im using colors for the grid for now but what should happen is the first 9 items are generated and when the user gets to the bottom of the page, the pagelistener will request more tiles (up until the pagesize reaches colors.length. However, the pagedgridview is _fetching automatically with the pageSize increment without any scroll behavior. I need this to work with my database when its figured out that way i dont make unnecessary reads.

What i have setup is a listview with one of its children as the PagedGridView<int, Color>. I also wrapped the body with a RefreshIndicator in attempt to manually notify the pagelistener. Either way, the gridview automatically increments the number of items by the pageSize (9) without any scroll behavior.

import 'package:flutter/material.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';

class InfiniteScroll extends StatefulWidget {
  const InfiniteScroll({super.key});

  @override
  State<InfiniteScroll> createState() => _InfiniteScrollState();
}

class _InfiniteScrollState extends State<InfiniteScroll> {
  final List<Color> _colors = List.generate(
    100,
    (index) => Color(index * 0xFFFFFF ~/ 1000).withOpacity(0.5),
  );

  static const int _pageSize = 9;
  final PagingController<int, Color> _pagingController =
      PagingController(firstPageKey: 0);

  @override
  void initState() {
    _pagingController.addPageRequestListener(_fetchPage);
    super.initState();
  }

  Future<void> _fetchPage(int pageKey) async {
    try {
      if (pageKey > _colors.length) {
        _pagingController.appendLastPage([]);
        return;
      }
      final newItesm = await Future.wait(List.generate(_pageSize,
              (index) => Future.delayed(const Duration(milliseconds: 50))))
          .then((_) => _colors.skip(pageKey).take(_pageSize).toList());

      final isLastPage = newItesm.length < _pageSize;
      if (isLastPage) {
        _pagingController.appendLastPage(newItesm);
      } else {
        final nextPageKey = pageKey + newItesm.length;
        _pagingController.appendPage(newItesm, nextPageKey);
      }
    } catch (e) {
      _pagingController.error = e;
      debugPrint(e.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: RefreshIndicator(
        onRefresh: () async => _pagingController.refresh(),
        child: ListView(
          children: [
            const Card(
              child: ListTile(
                title: Text("Infinite Scroll Pagination"),
                subtitle: Text("Infinite Scroll Pagination"),
                trailing: Icon(Icons.arrow_forward_ios),
              ),
            ),
            PagedGridView<int, Color>(
              pagingController: _pagingController,
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 3,
                mainAxisSpacing: 4.0,
                crossAxisSpacing: 4.0,
              ),
              builderDelegate: PagedChildBuilderDelegate<Color>(
                itemBuilder: (context, item, index) {
                  return Container(
                    color: item,
                    child: InkWell(
                      onTap: () {
                        debugPrint("Color: $item");
                      },
                      child: Center(
                        child: Text(
                          index.toString(),
                          style: const TextStyle(fontSize: 20),
                        ),
                      ),
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _pagingController.dispose();
    super.dispose();
  }
}

Solution

  • Seems like the ListView is not lazy loading. Removing the Card from the Listview and changing the Listview to a LayoutBuilder worked for me.

        body: RefreshIndicator(
            onRefresh: () async => _pagingController.refresh(),
            child: LayoutBuilder(builder: (context, constraints) {
              return PagedGridView<int, Color>(
                pagingController: _pagingController,
                shrinkWrap: true,
                // physics: const NeverScrollableScrollPhysics(),
                gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 3,
                  mainAxisSpacing: 4.0,
                  crossAxisSpacing: 4.0,
                ),
                builderDelegate: PagedChildBuilderDelegate<Color>(
                  itemBuilder: (context, item, index) {
                    return Container(
                      color: item,
                      child: InkWell(
                        onTap: () {
                          debugPrint("Color: $item");
                        },
                        child: Center(
                          child: Text(
                            index.toString(),
                            style: const TextStyle(fontSize: 20),
                          ),
                        ),
                      ),
                    );
                  },
                ),
              );
            }),
          ),
    

    Here's where I placed the Card.

    
          appBar: PreferredSize(
            preferredSize: const Size.fromHeight(50), // here the desired height
            child: Card(
              child: ListTile(
                title: Text("Infinite Scroll Pagination"),
                subtitle: Text("Infinite Scroll Pagination"),
                trailing: Icon(Icons.arrow_forward_ios),
              ),
            ),
          ),