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
623 stars 210 forks source link

Does not wait for user to scroll to end (continues loading data from API, till all the data fetched.) #203

Closed UMEGS closed 1 year ago

UMEGS commented 2 years ago

I have been using this module, but there is a problem, it does not wait for the user to scroll to the end and then load the next data. It continually loads new data, until the data fetching is done. let's say I have more than 500 pages of data and par page 10, the module will continuously load all 500 pages. I used invisibleItemsThreshold. but it also not working.

final searchParams;
final PagingController<int, MovieCard> _pagingController = PagingController(firstPageKey: 1, invisibleItemsThreshold: 1,);

@override
  void initState() {
    _pagingController.addPageRequestListener((pageKey) =>loadNextData(pageKey));
    super.initState();
  }
MovieService.fetchMoviesList(endPointParams: param).then((value) {
      MovieModelList movieModelList = MovieModelList.fromJson(value['movies']);
      bool hasNext = value['hasNext'];
      List<MovieCard> movieCardList = movieModelList.movies.map((movie) => MovieCard(movie: movie)).toList();

      if (hasNext) {
        _pagingController.appendPage(movieCardList, pageKey + 1);
      } else {
        _pagingController.appendLastPage(movieCardList);
      }
    }).catchError((err) {
      _pagingController.error = err;
      setState(() {
        _hasNext = false;
      });
    });
  }

loadNextData(int pageKey) {
    const limit = 10;
    if (searchParams['isRefresh'] == '1') {
      searchParams['isRefresh'] = '0';
      print('refreshed');

      _pagingController.refresh();
    }

    String filterParam = 'quality=${searchParams['quality']}'
        '&minimum_rating=${searchParams['rating']}'
        '&genre=${searchParams['genre']}'
        '&sort_by=${searchParams['sortBy']}'
        '&order_by=${searchParams['orderBy']}'
        '&query_term=${searchParams['searchQuery']}';

    String param = 'limit=$limit&page=$pageKey&$filterParam';
    print(param);

    MovieService.fetchMoviesList(endPointParams: param).then((value) {
      MovieModelList movieModelList = MovieModelList.fromJson(value['movies']);
      bool hasNext = value['hasNext'];
      List<MovieCard> movieCardList = movieModelList.movies.map((movie) => MovieCard(movie: movie)).toList();

      if (hasNext) {
        _pagingController.appendPage(movieCardList, pageKey + 1);
      } else {
        _pagingController.appendLastPage(movieCardList);
      }
    }).catchError((err) {
      _pagingController.error = err;
      setState(() {
        _hasNext = false;
      });
    });
  }

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

@override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;

    return PagedGridView<int, MovieCard>(
      shrinkWrap: true,
      showNewPageProgressIndicatorAsGridChild: true,
      showNewPageErrorIndicatorAsGridChild: true,
      showNoMoreItemsIndicatorAsGridChild: true,
      pagingController: _pagingController,
      physics: const NeverScrollableScrollPhysics(),
      padding: EdgeInsets.all(10),
      addAutomaticKeepAlives: true,
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
        mainAxisSpacing: 25.0,
        childAspectRatio: (size.width / size.height / .7),
      ),
      builderDelegate: PagedChildBuilderDelegate<MovieCard>(
        itemBuilder: (context, item, index) => item,
      ),
    );
  }
clragon commented 2 years ago

Your code does not work because you are using shrinkwrap: https://api.flutter.dev/flutter/widgets/ScrollView/shrinkWrap.html which makes your entire scrollview build all its children at once and therefore breaks the way the paged view detects user scroll location. The package is working as intended.

HafizAlwi commented 2 years ago

facing the same issue right now, even without shrinkwrap: using pagedlistview.

abdalazeez1 commented 2 years ago

same error here any solution

`

    import '../../../../../generated/l10n.dart';
    import '../../../../../injection/service_locator.dart';
    import '../../../domain/entities/Product.dart';
    import '../widget/product.dart';

    class TopSellingProductScreen extends StatefulWidget {
      const TopSellingProductScreen({Key? key}) : super(key: key);
      static String path = 'top-selling';
      static String name = 'top-selling';
      static Page pageBuilder(BuildContext context, GoRouterState state) =>
          MaterialPage(
            key: state.pageKey,
            child: BlocProvider.value(
              value: si<ProductBloc>(),
              child: const TopSellingProductScreen(),
            ),
          );
      @override
      State<TopSellingProductScreen> createState() =>
          _TopSellingProductScreenState();
    }
    class _TopSellingProductScreenState extends State<TopSellingProductScreen> {
      final PagingController<int, Product> pagingController = PagingController(
        firstPageKey: 1,
      );
      @override
      void initState() {
        pagingController.addPageRequestListener((pageKey) {
          context.read<ProductBloc>().add(GetTopProduct(pageKey: pageKey));
        });
        super.initState();
      }
      @override
      Widget build(BuildContext context) {
        final s = S.of(context);
        return BlocListener<ProductBloc, ProductState>(
          listener: (context, state) {
            if (state.topProducts.isLoaded) {
              final List<Product> data = state.topProducts.getDataWhenSuccess ?? [];
              print('ggggggggggggggggg : ${data.length}');
              final isLastPage = (data.length) < pageSize;
              if (isLastPage) {
                pagingController.appendLastPage(data);
              } else {
                final nextPageKey = state.pageKeyTopSellingProduct + data.length;
                pagingController.appendPage(data, nextPageKey);
              }
            }
            if (state.topProducts.isError) {
              pagingController.error = state.topProducts.error;
            }
          },
          child: Scaffold(
            appBar: AppBar(
              title: Text(s.top_selling_product),
            ),
            body: PagedGridView(
                pagingController: pagingController,
                builderDelegate: PagedChildBuilderDelegate<Product>(
                  itemBuilder: (context, item, index) =>
                      ProductWidget(index: index, product: item),
                ),
                gridDelegate: kConfigurationGrid),
          ),
        );
      }
    }

`

Said-Khamis commented 1 year ago

The same problem here... Is there any solution?

MatyasK commented 1 year ago

I have the same problem when I tried with bloc, and with the example from raywenderlich.com, is there any solution for this? since this makes this package useless

Haileman11 commented 1 year ago

Your code does not work because you are using shrinkwrap: https://api.flutter.dev/flutter/widgets/ScrollView/shrinkWrap.html which makes your entire scrollview build all its children at once and therefore breaks the way the paged view detects user scroll location. The package is working as intended.

Thank you man, you saved me days of debugging.

AbhishekYadav03 commented 1 year ago

Your code does not work because you are using shrinkwrap: https://api.flutter.dev/flutter/widgets/ScrollView/shrinkWrap.html which makes your entire scrollview build all its children at once and therefore breaks the way the paged view detects user scroll location. The package is working as intended.

Thank You man.

mfs-ariel-rios commented 1 year ago

I have the same problem, I don't know if I'm implementing something wrong but I attach an image of the widget tree I currently have. The container I have to limit the size of the view and not show the other elements, to see the effect of the scroll, but even with that I can not make the elements do not load on user demand, all elements are loaded. I have a version of flutter 2.10.5 Dart sdk 2.16.2 and I use a path management package called Modular. But I don't think that this dependency causes something, and also I tried with different versions of this package without solution (3.1.0, 3.0.0, and 2.3.0). I add the code, from my list, because I have simplified it more to avoid conflicts of other elements, but I have no success.

I already tried with PagedList and PagedList. Very possibly I am doing something wrong, but I can not visualize it.

Screenshot 2023-06-26 at 9 04 41

I am bringing 2 elements per page and there are 16 elements approximately.

My code is:

class MMItemsScreen extends StatefulWidget {
  const MMItemsScreen({Key? key}) : super(key: key);

  @override
  State<MMItemsScreen> createState() => _MMItemsScreenState();
}

class _MMItemsScreenState extends State<MMItemsScreen> {
  final currentPage = 0;
  final nextPage = 1;
   final PagingController<int, MMProfile> _pagingController =
      PagingController(firstPageKey: 1, invisibleItemsThreshold: 4);

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

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

  Future<void> getFetchItems() async {

    try {
      final items = await _getItems(params);
      final isLastPage = currentPage == nextPage; // on _getItems setting that values
      if (isLastPage) {
        _pagingController.appendLastPage(currentList);
      } else {
        _pagingController.appendPage(currentList, nextPage);
      }
    } catch (error) {
      if (kDebugMode) {
        print(error);
      }
      pagingController.error = error;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Merchants'),
      ),
      body: Stack(
        children: const [Container(
        height: 63,
        child: CustomScrollView(
          slivers: [
            PagedSliverList<int, MMProfile>(
              pagingController: _pagingController,
              builderDelegate: PagedChildBuilderDelegate<MMProfile>(
                itemBuilder: (context, item, index) => mMCard(item),
              ),
            )
          ],
        ),
      )],
      ),
    );
  }
}

In the last image I show my local backend with the multiple calls made one after the other, without scrolling. Screenshot 2023-06-26 at 9 38 41

If you can see something that I am doing wrong, I would appreciate it, or if you have gone through something similar, and have a solution. Thank you very much :)

** This is a simplification to not add all the code, but the operation is simulated and simplified, so some names or attributes could be wrong, because I wrote it directly, but the construction of the elements is the same and is a reference to my situation.

Another thing that happens to me in iOS is when I'm scrolling, it suddenly moves me down or up depending on the movement, that does not happen in Android.

I hope I made myself clear.