EdsonBueno / infinite_scroll_pagination

Flutter package to help you lazily load and display pages of items as the user scrolls down your screen.
https://pub.dev/packages/infinite_scroll_pagination
MIT License
612 stars 202 forks source link

All items are loaded all at once in this simple repro case, why? #281

Closed andynewman10 closed 11 months ago

andynewman10 commented 11 months ago

First of all, my apology if this issue has been raised before. What I am describing here is an incredibly common scenario where a page consists of a stack of items laid out vertically, the last of which is a ListView that needs to be progressively populated as the user scrolls down the page. Without PagedListView, I would use a ListView that would display all items, causing the page to be scrollable downwards until the last item is reached by the user.

Consider the following simple code that stacks vertically two Text widgets and one PagedListView holding up to 300 items.

If you run this code, all 300 items will be fetched, why? I searched the github issues and read about Slivers, but the use case described in these issues seem considerably more complex than my (extremely simple) code below.

What is wrong with the code/approach below? I would expect PagedListView to automatically fetch more data as the user scrolls down the page, in chunks of 10 items each time.

class _MyHomePageState extends State<MyHomePage> {
  static const int numberOfPostsPerRequest = 10;

  final PagingController<int, int> pagingController =
      PagingController(firstPageKey: 0);

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

  @override
  void initState() {
    pagingController.addPageRequestListener((pageKey) {
      fetchPage(pageKey);
    });
    super.initState();
  }

  // This function creates a paginable list of 300 items
  Future<List<int>> getItems(int offset, int limit) async {
    print("getItems($offset,$limit)");
    var itemList = <int>[];
    for (int i = offset; i < (offset + limit); i++) {
      if (i < 300) {
        itemList.add(i);
      }
    }
    return itemList;
  }

  Future<void> fetchPage(int pageKey) async {
    try {
      final postList = await getItems(
          pageKey * numberOfPostsPerRequest, numberOfPostsPerRequest);
      final isLastPage = postList.length < numberOfPostsPerRequest;
      if (isLastPage) {
        pagingController.appendLastPage(postList);
        debugPrint('All pages ended. This is the last page');
      } else {
        final nextPageKey = pageKey + 1;
        pagingController.appendPage(postList, nextPageKey);
      }
    } catch (error) {
      print('error --> $error');
      pagingController.error = error;
    }
  }

  Widget _createPagedListView() {
    return PagedListView<int, int>(
      physics: const ClampingScrollPhysics(),
      scrollDirection: Axis.vertical,
      shrinkWrap: true,
      pagingController: pagingController,
      builderDelegate: PagedChildBuilderDelegate<int>(
        animateTransitions: true,
        itemBuilder: (context, item, index) {
          return Text("Item: $item");
        },
      ),
    );
  }

  Widget columnize(List<Widget> children) {
    return ListView(
        physics: const ClampingScrollPhysics(),
        shrinkWrap: true,
        children: children);
  }

  // Not used (alternate method)
  Widget columnizeOther(List<Widget> children) {
    return Column(children: children);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: columnize(
        <Widget>[
          const Text(
            'Experimenting with PagedListView',
          ),
          Text(
            'HELLO',
            style: Theme.of(context).textTheme.headlineMedium,
          ),
          _createPagedListView()
        ],
      ),
    );
  }
}
andynewman10 commented 11 months ago

Solved this by using a PagedSliverList. The whole sliver vs box widget concept seems a bit weird...