Flutter package to help you lazily load and display pages of items as the user scrolls down your screen.

Overview

Package Logo with Flutter Favorite Badge

Chosen as a Flutter Favorite by the Flutter Ecosystem Committee

Pub.dev Badge GitHub Build Badge Code Coverage Badge Gitter Badge Effective Dart Badge MIT License Badge Flutter Platform Badge


Infinite Scroll Pagination

Unopinionated, extensible and highly customizable package to help you lazily load and display small chunks of items as the user scrolls down the screen – known as infinite scrolling pagination, endless scrolling pagination, auto-pagination, lazy loading pagination, progressive loading pagination, etc.

Designed to feel like part of the Flutter framework.

Example Project

Tutorial

By raywenderlich.com (step-by-step, hands-on, in-depth and illustrated).

Usage

class CharacterListView extends StatefulWidget {
  @override
  _CharacterListViewState createState() => _CharacterListViewState();
}

class _CharacterListViewState extends State<CharacterListView> {
  static const _pageSize = 20;

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

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

  Future<void> _fetchPage(int pageKey) async {
    try {
      final newItems = await RemoteApi.getCharacterList(pageKey, _pageSize);
      final isLastPage = newItems.length < _pageSize;
      if (isLastPage) {
        _pagingController.appendLastPage(newItems);
      } else {
        final nextPageKey = pageKey + newItems.length;
        _pagingController.appendPage(newItems, nextPageKey);
      }
    } catch (error) {
      _pagingController.error = error;
    }
  }

  @override
  Widget build(BuildContext context) => 
      // Don't worry about displaying progress or error indicators on screen; the 
      // package takes care of that. If you want to customize them, use the 
      // [PagedChildBuilderDelegate] properties.
      PagedListView<int, CharacterSummary>(
        pagingController: _pagingController,
        builderDelegate: PagedChildBuilderDelegate<CharacterSummary>(
          itemBuilder: (context, item, index) => CharacterListItem(
            character: item,
          ),
        ),
      );

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

For more usage examples, please take a look at our cookbook or check out the example project.

Features

API Overview

API Diagram

Comments
  • When an initial page is provided to the widget to refresh it, and the second page was the last page loaded beforehand, the second page will not be requested when it should.

    When an initial page is provided to the widget to refresh it, and the second page was the last page loaded beforehand, the second page will not be requested when it should.

    ~~The data I'm paginating can occasionally change on the server. If I detect this has happened while paginating, I must invalidate the data and clear everything.~~

    ~~Basically, I'm doing this (simplified with state management removed):~~

    Future<void> load() async {
      final newPage = await loadData()
      if (oldPage.isInvalid(newPage) {
        _pagingController.value = PagingState(
          nextPageKey: 0,
          itemList: null,
          error: null,
        );
      } else {
        _pagingController.value = PagingState(
          nextPageKey: newData.length,
          itemList: newData.items,
        );
      }
    }
    

    ~~This load function is called by a listener added with addPageRequestListener.~~

    ~~The above code, however, doesn't usually work. Instead, the widget will just stop updating, showing the loading indicator at the bottom of the old page indefinitely.~~

    opened by hacker1024 14
  • Cant refresh again when previous refresh is still loading.

    Cant refresh again when previous refresh is still loading.

    When you call controller.refresh() you have to wait till the previous addPageRequestListenerhas finished and append. How do you cancel the previous future and just refresh again?

    This happened to me when the user wants to switch filters quickly. So every time a filter setting is applied, controller.refresh() is called with the new setting. But when the refresh is called too quickly before the previous one can complete it doesn't register and addPageRequestListener isn't called.

    opened by Mayb3Nots 11
  • [Feature Request] PageView support

    [Feature Request] PageView support

    Some of the grids in my app can be opened into a PageView. When the end of the pageview is reached, new data should be loaded and the grid should be also updated with that data. Using the pagingcontroller with the grid should be easy enough, and triggering an update from somewhere else should also work.

    Could we get support for pageviews? I assume the PagedSliverBuilder is a vertical scroll view, and not suitable for this task.

    opened by clragon 11
  • Is it possible to handle scroll UP and DOWN to load more?

    Is it possible to handle scroll UP and DOWN to load more?

    I see that we can handle scroll DOWN to load more, but is it possible to handle scroll UP as well to load more? For example, initial page is 2. So when I scroll to top I need to fetch page 1 etc.

    opened by valerybodak 10
  • [Question] Handle new items in addition to old ones

    [Question] Handle new items in addition to old ones

    I'm trying to build a chat messages list. You know: filling it with the latest messages as soon as the user opens the screen, letting the user see older messages with a lazy load (that is the focus of this package), but also update the list with new messages and scroll to them in case the user was in the bottom of it. You know, the regular Telegram and WhatsApp list of messages behavior.

    I've checked the example and I've seen how to add more elements to the end of the page. But is there a way to also handle new items, and scroll to them automatically in case the user was already at the bottom of the list?

    Congrats on this great package, by the way :·)

    opened by rocboronat 9
  • Dynamic pageKey

    Dynamic pageKey

    Assume we have 1000 items and loaded first page (10 item per page), If user delete one of items, and we load next page with offset 10, we lose an item! is it safe to ignore pageKey and use _pagingController.itemList.length?

    opened by sm2017 9
  • pageController  addPageRequestListener is called 4 times

    pageController addPageRequestListener is called 4 times

    As soon app opens addPageRequestListener is called 4x times and 4x times data is shown without reaching at the end of the first page or either scrolling, as I scroll forward, more data loads automatically without reaching at the end of the page.

    import 'dart:convert';
    import 'package:balaloka/constants/api_links.dart';
    import 'package:balaloka/modals/video_details.dart';
    import 'package:balaloka/widgets/video_card.dart';
    import 'package:flutter/material.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    import 'package:http/http.dart' as http;
    import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
    
    class CommonVideoListing extends StatefulWidget {
      final int favouriteVideos;
      final int userId;
      CommonVideoListing({required this.userId, required this.favouriteVideos});
      @override
      _CommonVideoListingState createState() => _CommonVideoListingState();
    }
    
    class _CommonVideoListingState extends State<CommonVideoListing> {
      late Video video;
      final PagingController<int, Video> _pagingController = PagingController(
        firstPageKey: 0,
      );
      static const _pageSize = 10;
      int pageNumber = 1;
    
      @override
      void dispose() {
       _pagingController.dispose();
        super.dispose();
      }
    
      @override
      void initState() {
        super.initState();
        _pagingController.addPageRequestListener((pageKey) {
         
          listingDataAPI(pageKey);
        });
       
      }
    
      Future<void> listingDataAPI(int pageKey) async {
        if (widget.userId == -100) {
          final SharedPreferences sharedPreferences =
              await SharedPreferences.getInstance();
          var parentId = sharedPreferences.getString('parentId');
    
          try {
            http.Response response = await http.get(Uri.parse(API.videoListingsAPI +
                'UserId=$parentId&queryText=&onlyfavouritevideos=${widget.favouriteVideos}&pagenumber=$pageNumber&pagesize=10'));
            var parsed = jsonDecode(response.body);
            video = Video.fromJson(parsed);
    
            final newItems = [video];
            final isLastPage = newItems[0].videoDetails.length < _pageSize;
            if (isLastPage) {
              _pagingController.appendLastPage(newItems);
            } else {
              final nextPageKey = pageKey + newItems[0].videoDetails.length;
              _pagingController.appendPage(newItems, nextPageKey);
            }
            setState(() {
              pageNumber += 1;
            });
          } catch (error) {
            _pagingController.error = error;
          }
        }
    
      }
    
    
      @override
      Widget build(BuildContext context) {
        final MediaQueryData queryData = MediaQuery.of(context);
        final width = queryData.size.width;
        return Padding(
            padding: EdgeInsets.only(
              left: 0.05 * width,
              right: 0.05 * width,
            ),
            child: CustomScrollView(
              slivers: [
                PagedSliverList<int, Video>(
                  pagingController: _pagingController,
                  builderDelegate: PagedChildBuilderDelegate<Video>(
                    itemBuilder: (context, item, i) {
                      return ListView.builder(
                        controller: ScrollController(),
                        shrinkWrap: true,
                        itemCount: item.videoDetails.length,
                        itemBuilder: (BuildContext context, int index) {
                          return VideoCard(
                            video: item,
                            context: context,
                            index: index,
                            userId: widget.userId,
                            videoId: -100,
                          );
                        },
                      );
                    },
                    noItemsFoundIndicatorBuilder: (context) {
                      return Text('No More Videos Found');
                    },
                    noMoreItemsIndicatorBuilder: (context) {
                      return Text('No More Videos Found');
                    },
                    newPageProgressIndicatorBuilder: (context) {
                      return Center(
                        child: CircularProgressIndicator(),
                      );
                    },
                    firstPageProgressIndicatorBuilder: (context) {
                      return Center(
                        child: CircularProgressIndicator(),
                      );
                    },
                  ),
                ),
              ],
            )
      }
    }
    
    opened by HaardikBhagtani 8
  • addPageRequestListener called after hiding the loading indicator

    addPageRequestListener called after hiding the loading indicator

    Hey @EdsonBueno , Thank you for this awesome library.

    I tried your simple example and the fetch is called again once the data is loaded causes to load the second page.

    I'm also wondering how to disable the loading indicator when calling the refresh() method?

    opened by awnigharbia 8
  • controll.onRefresh() make controller called twice

    controll.onRefresh() make controller called twice

    Hi ,

    I'm using TabBarView when change tab Item i call _con.pagingFoodsController.refresh();

    but what i got dubled items cuz the

    pagingFoodsController.addPageRequestListener((pageKey) { fetchFoodsPage(pageKey); });

    called twice

    Here my code : Container( child: FutureBuilder<List>( future: _con.getRestaurantFoodsCategories(), builder: (c, s) { if (s.hasData) { List tabs = new List();

                                      for (int i = 0; i < s.data.length; i++) {
                                        tabs.add(Tab(
                                          child: Text(
                                            s.data[i].name,
                                            style:
                                                TextStyle(color: Colors.black),
                                          ),
                                        ));
                                      }
                                      TabController tabController =
                                          new TabController(
                                              vsync: this, length: tabs.length);
                                      tabController.addListener(() {
                                        if (tabController.indexIsChanging) {
                                          _con.idOfCategory =
                                              s.data[tabController.index].id;
                                          _con.pagingFoodsController.refresh();
                                          print(s.data[tabController.index].id);
    
                                          print(
                                              "tab is animating. from active (getting the index) to inactive(getting the index) ");
                                        } else {
                                          //tab is finished animating you get the current index
                                          //here you can get your index or run some method once.
                                          //  print(tabController.index);
                                        }
                                      });
                                      return Container(
                                        height: 500,
                                        child: new MaterialApp(
                                          debugShowCheckedModeBanner: false,
                                          home: new Scaffold(
                                              appBar: new AppBar(
                                                backgroundColor: Theme.of(
                                                        context)
                                                    .scaffoldBackgroundColor,
                                                title: Padding(
                                                  padding: const EdgeInsets
                                                          .symmetric(
                                                      horizontal: 20),
                                                  child: ListTile(
                                                    dense: true,
                                                    contentPadding:
                                                        EdgeInsets.symmetric(
                                                            vertical: 0),
                                                    leading: Icon(
                                                      Icons.restaurant,
                                                      color: Theme.of(context)
                                                          .hintColor,
                                                    ),
                                                    title: Text(
                                                      S
                                                          .of(context)
                                                          .food_categories,
                                                      style: Theme.of(context)
                                                          .textTheme
                                                          .display1,
                                                    ),
                                                  ),
                                                ),
                                                bottom: new TabBar(
                                                  controller: tabController,
                                                  labelColor: Colors.black,
                                                  isScrollable: true,
                                                  tabs: List<Widget>.generate(
                                                      s.data.length,
                                                      (int index) {
                                                    return Tab(
                                                        text:
                                                            s.data[index].name);
                                                  }),
                                                ),
                                              ),
                                              body: new TabBarView(
                                                controller: tabController,
                                                children: List<Widget>.generate(
                                                    s.data.length, (int index) {
                                                  return PagedListView<int,
                                                      Food>.separated(
                                                    scrollDirection:
                                                        Axis.vertical,
                                                    primary: false,
                                                    shrinkWrap: false,
                                                    pagingController: _con
                                                        .pagingFoodsController,
                                                    builderDelegate:
                                                        PagedChildBuilderDelegate<
                                                            Food>(
                                                      itemBuilder: (context,
                                                          item, index) {
                                                        return FoodItemWidget(
                                                          food: item,
                                                          heroTag:
                                                              "menu_food_list",
                                                        );
                                                      },
                                                      noMoreItemsIndicatorBuilder:
                                                          (_) => Padding(
                                                        padding:
                                                            const EdgeInsets
                                                                .all(8.0),
                                                        child: ClipRRect(
                                                          borderRadius:
                                                              BorderRadius
                                                                  .circular(80),
                                                          child: RaisedButton(
                                                            disabledColor:
                                                                Colors.white,
                                                            onPressed: null,
                                                            child: Text(
                                                                "لا يوجد وجبات اخرى"),
                                                          ),
                                                        ),
                                                      ),
                                                    ),
                                                    separatorBuilder: (context,
                                                            index) =>
                                                        SizedBox(height: 10),
                                                  );
                                                }),
                                              )),
                                        ),
                                      );
                                    }
                                    if (s.hasError) print(s.error.toString());
                                    return Center(
                                        child: Text(s.hasError
                                            ? s.error.toString()
                                            : "Loading..."));
                                  },
                                ),
                              ),
    

    MVC controller class :

            pagingFoodsController.addPageRequestListener((pageKey) {
      //    _con.listenForOrders(pageKey);
      //  orderRepo.fetchPosts(orderRepo.nextUrl);
      fetchFoodsPage(pageKey);
    });
    

    Future fetchFoodsPage(pageKey) async { print("test"); // here is called twice !!! if (newFoodsItems.isNotEmpty) { if (newFoodsItems.first.category.id != idOfCategory) { newFoodsItems.clear(); if (pageKey == 0) newFoodsItems = await foodRepo.getFoodsOfRestaurant( idRestaurant, null, idOfCategory); else newFoodsItems = await foodRepo.getFoodsOfRestaurant( idRestaurant, foodRepo.nextUrlTFoodsOfRestaurant, idOfCategory); } } else { if (pageKey == 0) newFoodsItems = await foodRepo.getFoodsOfRestaurant( idRestaurant, null, idOfCategory); else newFoodsItems = await foodRepo.getFoodsOfRestaurant( idRestaurant, foodRepo.nextUrlTFoodsOfRestaurant, idOfCategory); } try { final isLastPage = newFoodsItems.length < _pageFoodsSize; if (isLastPage) { pagingFoodsController.appendLastPage(newFoodsItems); } else { final nextPageKey = pageKey + newFoodsItems.length; pagingFoodsController.appendPage(newFoodsItems, nextPageKey); } } catch (error) { pagingFoodsController.error = error; } }

    opened by heshesh2010 7
  • PagingController being prevented from rebuilding PagedListView

    PagingController being prevented from rebuilding PagedListView

    I've had a great time learning to use this plugin! After following your tutorial and documentation, I can't see what if anything I'm doing differently, but I'm having some issues. Within _fetchPage, right after _pagingController.appendPage() is called, I get the following exception:

    ════════ Exception caught by foundation library ════════════════════════════════
    The following assertion was thrown while dispatching notifications for PagingController<int, CardItem>:
    setState() or markNeedsBuild() called during build.
    
    This ValueListenableBuilder<PagingState<int, CardItem>> widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
    The widget on which setState() or markNeedsBuild() was called was: ValueListenableBuilder<PagingState<int, CardItem>>
        state: _ValueListenableBuilderState<PagingState<int, CardItem>>#c3dcd
    The widget which was currently being built when the offending call was made was: SliverList
        delegate: AppendedSliverChildBuilderDelegate#d62ee(estimated child count: 6)
    

    The second page of items is indeed shown, but past the second page, the loading spinner is rendered despite _nextPage not even being called a third time. No more items are added or displayed beyond these first two pages, even though more exist.

    Is there something I'm getting wrong, or is this a bug? I'd appreciate help with this :)

    Relevant widget: (replaced the itemBuilder with a simple text widget to simplify debugging)

    class ContentListView extends StatefulWidget {
      @override
      _ContentListViewState createState() => _ContentListViewState();
    }
    
    class _ContentListViewState extends State<ContentListView> {
      static const _pageSize = 5;
    
      final PagingController<int, CardItem> _pagingController =
          PagingController(firstPageKey: 0, invisibleItemsThreshold: 2);
    
      @override
      void initState() {
        _pagingController.addPageRequestListener((pageKey) {
          _fetchPage(pageKey);
        });
        super.initState();
      }
    
      @override
      void didUpdateWidget(ContentListView oldWidget) {
        _pagingController.refresh();
        super.didUpdateWidget(oldWidget);
      }
    
      Future<void> _fetchPage(int pageKey) async {
        try {
          final newItems = List<CardItem>();
          for (var i = 0; i < _pageSize; i++) {
            newItems
                .add(CardItem.fromProcess(Globals.oldProcessFeed.getNextProcess()));
          }
          final isLastPage = !Globals.oldProcessFeed.hasNextItem;
          if (isLastPage) {
            _pagingController.appendLastPage(newItems);
          } else {
            final nextPageKey = pageKey + 1;
            _pagingController.appendPage(newItems, nextPageKey);
          }
        } catch (error) {
          _pagingController.error = error;
          log(error);
        }
      }
    
      @override
      Widget build(BuildContext context) => PagedListView<int, CardItem>(
            pagingController: _pagingController,
            builderDelegate: PagedChildBuilderDelegate<CardItem>(
              itemBuilder: (context, item, index) =>
                  Text(item.process.processId).withTopPadding(300),
              newPageProgressIndicatorBuilder: (context) => Padding(
                  padding: const EdgeInsets.only(
                    top: 16,
                    bottom: 16,
                  ),
                  child: Center(child: SpinnerCircular())),
            ),
          );
    
      @override
      void dispose() {
        _pagingController.dispose();
        super.dispose();
      }
    }
    
    
    opened by NateWilliams2 7
  • Keeping scroll offset between tabs/pages

    Keeping scroll offset between tabs/pages

    Hello, I was unable to get PagedListView.separated to keep scroll offsets for each list after switching between tabs/pages. Might be related to #97. Here is a minimal example to reproduce:

    import 'package:flutter/material.dart';
    import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key? key}) : super(key: key);
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        final controller = DefaultTabController(
          length: 2,
          child: Scaffold(
            appBar: AppBar(
              title: Text('Test'),
              bottom: TabBar(
                isScrollable: true,
                tabs: [
                  Tab(text: 'A'),
                  Tab(text: 'B'),
                ],
              ),
            ),
            body: TabBarView(
              children: [
                PagedTopicListView(id: 0),
                PagedTopicListView(id: 1),
              ],
            ),
          ),
        );
        return controller;
      }
    }
    
    class PagedTopicListView extends StatefulWidget {
      PagedTopicListView({required this.id, Key? key}) : super(key: key);
    
      final int id;
    
      @override
      _PagedTopicListViewState createState() => _PagedTopicListViewState();
    }
    
    class _PagedTopicListViewState extends State<PagedTopicListView> {
      final _pagingController = PagingController<int, String>(firstPageKey: 0);
    
      @override
      void initState() {
        _pagingController.addPageRequestListener((pageKey) {
          _fetchPage(pageKey);
        });
        super.initState();
      }
    
      Future<void> _fetchPage(int pageKey) async {
        if (pageKey < 100) {
          _pagingController.appendPage(
              new List<int>.generate(10, (index) => index + pageKey)
                  .map((e) => e.toString())
                  .toList(),
              pageKey + 10);
        } else {
          _pagingController.appendLastPage([]);
        }
      }
    
      @override
      void dispose() {
        _pagingController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) => RefreshIndicator(
            child: PagedListView.separated(
              key: PageStorageKey(widget.id),
              pagingController: _pagingController,
              builderDelegate: PagedChildBuilderDelegate<String>(
                itemBuilder: (context, item, index) => Text(item),
              ),
              separatorBuilder: (context, index) => const Divider(),
            ),
            onRefresh: () => Future.sync(
              () => _pagingController.refresh(),
            ),
          );
    }
    

    Desired behavior: Scroll down in Tab A, switch to Tab B, then switch back, The app should return to Tab A's previous scroll offset.

    Actual: After switching back to Tab A, the app returns to the top of the list.

    opened by changlan 6
  • suggest] I would like a key-based pagination method.

    suggest] I would like a key-based pagination method.

    hello. Thanks for making such a nice plugin.

    Due to the nature of the infinity scroll, it would be better to make it work in a different way, so I suggest it. Instead of the page number system, it would be better to use 'key(post number) and next (or previous) quantity'. It seems that there is no need to fill in the missing part in the middle. In this way, if you search up to page 2 in the conventional way, write a new article and then search page 3, you can also solve the problem of one article being viewed repeatedly.

    _afterKey, _prevKey
    
    _fetchAfter(key?) {
      append - If key is null, _pageSize from the beginning
    }
    _fetchPrev(key) {
      prepend
    }
    

    If you do this, these problems will naturally be solved. https://github.com/EdsonBueno/infinite_scroll_pagination/issues/230 https://github.com/EdsonBueno/infinite_scroll_pagination/issues/231

    thank you.

    opened by crucifyer 0
  •  riverpod_infinite_scroll - Filtering

    riverpod_infinite_scroll - Filtering

    Hello,

    I'm trying to implement filtering but i'm having issue refresh the API call with the new filter key

    class HistoryStateNotifier extends PagedNotifier<int, Transaction> {
      Ref ref;
      String selectedFilter;
    
      HistoryStateNotifier({required this.ref, this.selectedFilter = 'all'})
          : super(
              load: (page, limit) => ref
                  .watch(apiProvider)
                  .getTransactions(page, limit, selectedFilter)
                  .then((value) => value.transactions),
              nextPageKeyBuilder: NextPageKeyBuilderDefault.mysqlPagination,
            );
    
      void setFilter(String filter) {
        selectedFilter = filter;
    
        // what i'm trying to reach is when the setFilter is called, 
        //the api call should be made again with the new filter
      }
    }
    
    final historyProvider =
        StateNotifierProvider<HistoryStateNotifier, PagedState<int, Transaction>>(
      (ref) => HistoryStateNotifier(
        ref: ref,
      ),
    );
    
    opened by Yasser-saud 0
  • Not able to scroll

    Not able to scroll

    I applied this package but unable to scroll this listview. its showing first page only. Please help me to solve this issue. following are my code excample

    Expanded(
                            child: FutureBuilder<UserPost>(
                              future: getUserPost(),
                              builder: (context, snapshot) {
                                if (snapshot.hasData) {
                                  return ListView.builder(
    itemCount: snapshot.data!.data!.length,
                                      itemBuilder: (context, i) {
    return Padding(
                                            padding: EdgeInsets.only(left: 5, right: 5),
                                            child: PagedListView<int,dynamic>(
                                              shrinkWrap: true,
                                              pagingController: _pagingController,
                                              builderDelegate: PagedChildBuilderDelegate<dynamic>(
                                                itemBuilder: (context,item,index) =>
                                              Card()
    )
    }
    )
    
    opened by Mohammad-taqi1212 0
  • How to update existed item on list view?

    How to update existed item on list view?

    Hi,

    Thank you for creating awesome library. I'm having a problem, how can i update item in specific page when using infinite_scroll_pagination

    Ex: Page 0[Rambutan, Tomato, Pear] Page 1[Apple, Orange, Cherry] Page 2[Pipeapple, Mango, Melon]

    Update Page 1[Apple, Banana, Cherry]

    Thank you,

    opened by cogivn 0
  • Problems when returning from RequestListener without change

    Problems when returning from RequestListener without change

    Hello, in my usecase i have a onSearch-method which refreshs the PagingController after a new searchterm was entered by the user. In the same method i use a dio-canceltoken to cancel the preceeding requests and start a new request by refreshing the controller. So if the preceeding request was canceled, i got a CancelationException which i catch and return from the RequestListener without doing anything, the refreshPage-Method is not called.

    After the catch and return the RequestListener doesn't get called anymore and i only see the CircularProgressIndicator spinning. I have no idea how to handle something like that. Do i have to do something with the PagingController after catching and return?

    Thanks in advance.

    Example:

    @override
    void initState() {
        _pagingController.addPageRequestListener(_listen);
        super.initState();
      }
    
     void _listen(pageKey) async {
        try {
          var watchlistResult = await _fetchWatchlist(pageKey, _filter);
          refreshPage(pageKey, watchlistResult);
        }
        on CancelationException catch(e){
          _pagingController.error = null;
          return;    
        } catch (error) {
          _pagingController.error = error;
        }
      }
    
     void refreshPage(
          int pageNumber, WatchlistCollectionListPagedResponse result) {
        final items = result.data;
        if (items == null) {
          return;
        }
    
    final isLastPage = result.totalPages == pageNumber + 1;
        if (isLastPage) {
          _pagingController.appendLastPage(items);
        } else {
          final nextPageKey = pageNumber + 1;
          _pagingController.appendPage(items, nextPageKey);
        }
      }
    
    void _onSearch(String searchString) async {
        _filter.filterString = searchString;
        _cancelToken.cancel("Abgebrochen");
        _cancelToken = CancelToken();
        _pagingController.refresh();
      }
    
    opened by kyi87 1
Releases(v3.1.0)
Owner
Edson Bueno
Author @raywenderlich.
Edson Bueno
A package that lets you include a cool, nice looking and validated Password TextFormField in your app to enhance user experience. The package is fully & easily modifiable.

A package that lets you include a cool, nice looking and validated Password TextFormField in your app to enhance user experience. The package is fully

Muhammad Hamza 20 Jun 7, 2022
With this package you can display numbers or any other text more nicely

flutter_number_animation With this package you can display numbers or any other text more nicely Preview Works with text too! How to use Add this to y

idan ben shimon 8 Jun 7, 2022
simplified man-pages, a tldr.sh client

Report bug · Request feature Table of contents Overview Screenshots CI Build and run Bugs and feature requests Contributing Creators Copyright and lic

Jayesh Nirve 84 Dec 27, 2022
A dart package to help you parse and evaluate infix mathematical expressions into their prefix and postfix notations.

A dart package to help you parse and evaluate infix mathematical expressions into their prefix and postfix notations.

Miguel Manjarres 2 Jan 28, 2022
A mobile map based application to help people everywhere around the world get help

Wonder This is a mobile application made by flutter. The application is called "Wonder" because it will help people everywhere around the world to get

Sara Nersisian 1 Dec 2, 2021
Library for help you make userbot or bot telegram and support tdlib telegram database and only support nodejs dart and google-apps-script

To-Do telegram client dart ✅️ support multi token ( bot / userbot ) ✅️ support bot and userbot ✅️ support telegram-bot-api local server ✅️ support tel

Azka Full Snack Developer:) 73 Jan 7, 2023
library to help you create database on local memory, support json local database inspired by lowdb

Licensed Licensed under the MIT License <http://opensource.org/licenses/MIT>. SPDX-License-Identifier: MIT Copyright (c) 2021 Azkadev <http://github.c

Azka Full Snack Developer:) 35 Oct 17, 2022
Flutter library to add gestures and animations to each Shape you draw on your canvas in your CustomPainter

Flutter library to bring your CustomPainter ?? to Life ✨ ⚡️ touchable library gives you the ability to add various gestures and animations to each Sha

Natesh Bhat 190 Jan 7, 2023
A flutter package with classes to help testing applications using the canvas

Canvas test helpers MockCanvas is a utility class for writing tests for canvas operations. It supports the same API as the regular Canvas class from d

Blue Fire 12 Jan 31, 2022
A simple package to help does handler with countries in Flutter

It's a simple package to help does handler with countries in [Dart] language and [Flutter] Framework. Usage Countries class Can access all countries s

Leonardo Rosa 1 Feb 20, 2022
A flutter package that allows you to transform your excel to json

excel_to_json A package that allows you to transform your excel to the following format: Excel To JSON Getting Started At current the package allows y

Vitor Amaral de Melo 0 Nov 7, 2022
Collects screen sizes and pixel densities for real iPhones, iPads, Google phones, Samsung phones, and more.

Device Sizes This package aggregates screen sizes and pixel densities for as many physical devices as possible. The purpose of this package is to help

Matt Carroll 16 Jan 8, 2023
Official Git of flutter code-push made by Chimera inc. If you want to get more info or seek for biz corporation, you can contact [email protected].

中文版 Chimera Flutter Code Push Chimera is a Dart compiler developed by ourselves, which generates interpretable and executable bytecode to implement co

Waytoon 21 Oct 6, 2022
Chuanying - what you see is what you get. 传影--所见即所得

传影--所见即所得 简介 从前 想要制作证件照,需要先把图片用QQ传到电脑,再用PS手动抠图; 看到一句喜欢的话,想要记到电脑里,需要一个字一个字用键盘打出来; 看到黑板上老师写的公式,想要记到Word里,需要用MathType一点点打出来; 但是有没有可能,只用手机拍照,就能搞定上面所有的事,一步

null 16 Apr 8, 2022
Flutter plugin to help experiment with different Color Schemes without pain.

Random Color Scheme Making a coherent Material Design theme is hard. This is a Flutter plugin that generates a random color pallet based on Material D

Bernardo Ferrari 77 Dec 6, 2022
A CLI tool to help generate dart classes from json returned from API

Json 2 Dart Command line utility Important note There is already a package called json2dart so this package will be called json2dartc ! This project w

Adib Mohsin 38 Oct 5, 2022
A CLI tool to help batch renaming files.

batch_rename A CLI tool to enable batch renaming of files. Installation Clone the repo and add bin/batch_rename.exe to PATH: gh repo clone POWRFULCOW8

Diego Domínguez Melo 0 Nov 3, 2021
Flutter Cool Random User Generate 🔥🔥

Flutter Cool Random User Generate ????

Hmida 8 Sep 10, 2022
Application that simplifies the search process in several supermarkets, allowing the user to define the shopping list in a few minutes.

economiz Application that solves the price research process in different supermarkets, facilitating and simplifying this process for the user. Getting

Guilherme Henrique 1 Dec 29, 2021