Giter Site home page Giter Site logo

edsonbueno / infinite_scroll_pagination Goto Github PK

View Code? Open in Web Editor NEW
584.0 4.0 192.0 4.04 MB

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

Home Page: https://pub.dev/packages/infinite_scroll_pagination

License: MIT License

Kotlin 0.26% Ruby 0.85% Swift 0.25% Objective-C 0.02% Dart 98.61%
flutter pagination infinite-scroll infinite-scrolling endless-scroll endless-scrolling endless-scrolling-flutter load-more-flutter load-more

infinite_scroll_pagination's Introduction

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 BeerListView extends StatefulWidget {
  @override
  _BeerListViewState createState() => _BeerListViewState();
}

class _BeerListViewState extends State<BeerListView> {
  static const _pageSize = 20;

  final PagingController<int, BeerSummary> _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.getBeerList(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, BeerSummary>(
        pagingController: _pagingController,
        builderDelegate: PagedChildBuilderDelegate<BeerSummary>(
          itemBuilder: (context, item, index) => BeerListItem(
            beer: 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

infinite_scroll_pagination's People

Contributors

cenumi avatar clragon avatar edson-mgm avatar edsonbueno avatar hacker1024 avatar kitkat255 avatar luterium avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

infinite_scroll_pagination's Issues

retryLastRequest() missing

Hi, I just upgraded to 2.2.3 version. Did you just

Fixes a bug where manually resetting to a previous page would stop requesting subsequent pages.

by deleting retryLastRequest method?
It's breaking change. What is substitution of this method?

Exception only when using RefreshIndicator

When using the RefreshIndicator am getting the below exception. If I remove the RefreshIndicator widget, all works fine as expected. The widget shown below is used in other widgets which uses CustomScrollView.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:womenly/models/post_model.dart';
import 'package:womenly/services/firestore_database.dart';
import 'package:womenly/widgets/single_post_card.dart';

class PostsList extends StatefulWidget {
  final bool showOnlyFav;
  final bool showPopular;
  final String userId;
  final String label;
  final String category;
  final String favUserId;

  PostsList({
    this.showOnlyFav = false,
    this.showPopular = false,
    this.userId,
    this.category,
    this.label,
    this.favUserId,
  });

  @override
  _PostsListState createState() => _PostsListState();
}

class _PostsListState extends State<PostsList>
    with AutomaticKeepAliveClientMixin<PostsList> {
  static const _pageSize = 4;
  DocumentSnapshot lastDoc;

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

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

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

  Future<void> _fetchPage(int pageKey) async {
    try {
      final querySnapshot = await FirestoreDatabase().postsStream(
          favUserId: widget.favUserId,
          category: widget.category,
          userId: widget.userId,
          label: widget.label,
          lastDoc: lastDoc,
          count: _pageSize,
          showPopular: widget.showPopular,
          showOnlyFav: widget.showOnlyFav);

      List<QueryDocumentSnapshot> docs = querySnapshot.docs;

      final isLastPage = docs.length < _pageSize;
      lastDoc = docs.last;

      if (isLastPage) {
        _pagingController.appendLastPage(docs);
      } else {
        final nextPageKey = pageKey + docs.length;
        _pagingController.appendPage(docs, nextPageKey);
      }
    } catch (error) {
      _pagingController.error = error;
    }
  }

  @override
  Widget build(BuildContext context) {
    return RefreshIndicator(
      onRefresh: () => Future.sync(() => _pagingController.refresh()),
      child: PagedSliverList<int, QueryDocumentSnapshot>(
        pagingController: _pagingController,
        builderDelegate: PagedChildBuilderDelegate<QueryDocumentSnapshot>(
          itemBuilder: (context, item, index) =>
              SingleDesignWidget(PostModel.fromMap(item.data())),
        ),
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

Below is the exception.

Performing hot restart...
Syncing files to device Redmi Note 7 Pro...
Restarted application in 2,302ms.
I/flutter (13686): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (13686): The following assertion was thrown building RefreshIndicator(dependencies: [_InheritedTheme,
I/flutter (13686): _EffectiveTickerMode, _LocalizationsScope-[GlobalKey#f827c]], state:
I/flutter (13686): RefreshIndicatorState#4a99c(tickers: tracking 2 tickers)):
I/flutter (13686): A RenderViewport expected a child of type RenderSliver but received a child of type RenderStack.
I/flutter (13686): RenderObjects expect specific types of children because they coordinate with their children during
I/flutter (13686): layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a
I/flutter (13686): RenderSliver does not understand the RenderBox layout protocol.
I/flutter (13686): 
I/flutter (13686): The RenderViewport that expected a RenderSliver child was created by:
I/flutter (13686):   ViewportIgnorePointer-[GlobalKey#920d1] ← Semantics_PointerListenerListenerI/flutter (13686):   _GestureSemanticsRawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#8768b] ←
I/flutter (13686):   _PointerListenerListener_ScrollableScope_ScrollSemantics-[GlobalKey#10bbd] ←
I/flutter (13686):   RepaintBoundary ← ⋯
I/flutter (13686): 
I/flutter (13686): The RenderStack that did not match the expected child type was created by:
I/flutter (13686):   StackRefreshIndicatorPostsListViewportIgnorePointer-[GlobalKey#920d1] ← SemanticsI/flutter (13686):   _PointerListenerListener_GestureSemanticsI/flutter (13686):   RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#8768b] ← _PointerListenerListener
I/flutter (13686):   ← ⋯
I/flutter (13686): 
I/flutter (13686): The relevant error-causing widget was:
I/flutter (13686):   RefreshIndicator file:///D:/Flutter/womenly/lib/screens/posts/posts_list.dart:83:12
I/flutter (13686): 
I/flutter (13686): When the exception was thrown, this was the stack:
I/flutter (13686): #0      ContainerRenderObjectMixin.debugValidateChild.<anonymous closure> (package:flutter/src/rendering/object.dart:3123:9)
I/flutter (13686): #1      ContainerRenderObjectMixin.debugValidateChild (package:flutter/src/rendering/object.dart:3150:6)
I/flutter (13686): #2      MultiChildRenderObjectElement.insertRenderObjectChild (package:flutter/src/widgets/framework.dart:6191:25)
I/flutter (13686): #3      RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:5805:35)
I/flutter (13686): #4      RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5501:5)
I/flutter (13686): #5      MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6232:11)
I/flutter (13686): ...     Normal element mounting (17 frames)
I/flutter (13686): #22     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #23     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): #24     _ViewportElement.mount (package:flutter/src/widgets/viewport.dart:225:11)
I/flutter (13686): ...     Normal element mounting (127 frames)
I/flutter (13686): #151    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #152    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (103 frames)
I/flutter (13686): #255    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #256    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (208 frames)
I/flutter (13686): #464    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #465    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (70 frames)
I/flutter (13686): #535    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #536    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (210 frames)
I/flutter (13686): #746    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #747    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (156 frames)
I/flutter (13686): #903    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #904    Element.updateChild (package:flutter/src/widgets/framework.dart:3324:20)
I/flutter (13686): #905    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4652:16)
I/flutter (13686): #906    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
I/flutter (13686): #907    Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
I/flutter (13686): #908    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2730:33)
I/flutter (13686): #909    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:913:20)
I/flutter (13686): #910    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
I/flutter (13686): #911    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
I/flutter (13686): #912    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1055:9)
I/flutter (13686): #913    SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:864:7)
I/flutter (13686): (elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
I/flutter (13686): 
I/flutter (13686): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (13686): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (13686): The following assertion was thrown building PostsList(state: _PostsListState#09c9b):
I/flutter (13686): A RenderViewport expected a child of type RenderSliver but received a child of type RenderErrorBox.
I/flutter (13686): RenderObjects expect specific types of children because they coordinate with their children during
I/flutter (13686): layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a
I/flutter (13686): RenderSliver does not understand the RenderBox layout protocol.
I/flutter (13686): 
I/flutter (13686): The RenderViewport that expected a RenderSliver child was created by:
I/flutter (13686):   ViewportIgnorePointer-[GlobalKey#920d1] ← Semantics_PointerListenerListenerI/flutter (13686):   _GestureSemanticsRawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#8768b] ←
I/flutter (13686):   _PointerListenerListener_ScrollableScope_ScrollSemantics-[GlobalKey#10bbd] ←
I/flutter (13686):   RepaintBoundary ← ⋯
I/flutter (13686): 
I/flutter (13686): The RenderErrorBox that did not match the expected child type was created by:
I/flutter (13686):   ErrorWidget-[#a7044] ← RefreshIndicatorPostsListViewportIgnorePointer-[GlobalKey#920d1] ←
I/flutter (13686):   Semantics_PointerListenerListener_GestureSemanticsI/flutter (13686):   RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#8768b] ← _PointerListenerListener
I/flutter (13686):   ← ⋯
I/flutter (13686): 
I/flutter (13686): The relevant error-causing widget was:
I/flutter (13686):   PostsList file:///D:/Flutter/womenly/lib/screens/dashboard/dashboard_screen.dart:43:9
I/flutter (13686): 
I/flutter (13686): When the exception was thrown, this was the stack:
I/flutter (13686): #0      ContainerRenderObjectMixin.debugValidateChild.<anonymous closure> (package:flutter/src/rendering/object.dart:3123:9)
I/flutter (13686): #1      ContainerRenderObjectMixin.debugValidateChild (package:flutter/src/rendering/object.dart:3150:6)
I/flutter (13686): #2      MultiChildRenderObjectElement.insertRenderObjectChild (package:flutter/src/widgets/framework.dart:6191:25)
I/flutter (13686): #3      RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:5805:35)
I/flutter (13686): #4      RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5501:5)
I/flutter (13686): ...     Normal element mounting (17 frames)
I/flutter (13686): #21     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #22     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): #23     _ViewportElement.mount (package:flutter/src/widgets/viewport.dart:225:11)
I/flutter (13686): ...     Normal element mounting (127 frames)
I/flutter (13686): #150    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #151    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (103 frames)
I/flutter (13686): #254    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #255    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (208 frames)
I/flutter (13686): #463    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #464    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (70 frames)
I/flutter (13686): #534    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #535    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (210 frames)
I/flutter (13686): #745    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #746    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (156 frames)
I/flutter (13686): #902    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #903    Element.updateChild (package:flutter/src/widgets/framework.dart:3324:20)
I/flutter (13686): #904    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4652:16)
I/flutter (13686): #905    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
I/flutter (13686): #906    Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
I/flutter (13686): #907    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2730:33)
I/flutter (13686): #908    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:913:20)
I/flutter (13686): #909    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
I/flutter (13686): #910    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
I/flutter (13686): #911    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1055:9)
I/flutter (13686): #912    SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:864:7)
I/flutter (13686): (elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
I/flutter (13686): 
I/flutter (13686): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (13686): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (13686): The following assertion was thrown building Listener:
I/flutter (13686): A RenderViewport expected a child of type RenderSliver but received a child of type RenderErrorBox.
I/flutter (13686): RenderObjects expect specific types of children because they coordinate with their children during
I/flutter (13686): layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a
I/flutter (13686): RenderSliver does not understand the RenderBox layout protocol.
I/flutter (13686): 
I/flutter (13686): The RenderViewport that expected a RenderSliver child was created by:
I/flutter (13686):   ViewportIgnorePointer-[GlobalKey#920d1] ← Semantics_PointerListenerListenerI/flutter (13686):   _GestureSemanticsRawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#8768b] ←
I/flutter (13686):   _PointerListenerListener_ScrollableScope_ScrollSemantics-[GlobalKey#10bbd] ←
I/flutter (13686):   RepaintBoundary ← ⋯
I/flutter (13686): 
I/flutter (13686): The RenderErrorBox that did not match the expected child type was created by:
I/flutter (13686):   ErrorWidget-[#e9942] ← PostsListViewportIgnorePointer-[GlobalKey#920d1] ← SemanticsI/flutter (13686):   _PointerListenerListener_GestureSemanticsI/flutter (13686):   RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#8768b] ← _PointerListenerListener
I/flutter (13686):_ScrollableScope ← ⋯
I/flutter (13686): 
I/flutter (13686): The relevant error-causing widget was:
I/flutter (13686):   CustomScrollView file:///D:/Flutter/womenly/lib/screens/dashboard/dashboard_screen.dart:10:14
I/flutter (13686): 
I/flutter (13686): When the exception was thrown, this was the stack:
I/flutter (13686): #0      ContainerRenderObjectMixin.debugValidateChild.<anonymous closure> (package:flutter/src/rendering/object.dart:3123:9)
I/flutter (13686): #1      ContainerRenderObjectMixin.debugValidateChild (package:flutter/src/rendering/object.dart:3150:6)
I/flutter (13686): #2      MultiChildRenderObjectElement.insertRenderObjectChild (package:flutter/src/widgets/framework.dart:6191:25)
I/flutter (13686): #3      RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:5805:35)
I/flutter (13686): #4      RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5501:5)
I/flutter (13686): ...     Normal element mounting (9 frames)
I/flutter (13686): #13     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #14     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): #15     _ViewportElement.mount (package:flutter/src/widgets/viewport.dart:225:11)
I/flutter (13686): ...     Normal element mounting (127 frames)
I/flutter (13686): #142    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #143    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (103 frames)
I/flutter (13686): #246    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #247    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (208 frames)
I/flutter (13686): #455    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (13686): #456    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (13686): ...     Normal element mounting (70 frames)

Completed list indicator

Thanks for this awesome plugin! It works like a charm for purposes like you explained in doc.
However I did find a way to stop displaying the newPageProgressIndicator once the whole list has been loaded.

I think I have to notify the dataSource that the list is completed but I cannot find a way to do this...
Could you explain to me how to do this please?

Null safety

With null safety increasing in popularity, it'd be great if this package could implement it.

poping the screen before the page loads crash the app on ios

hello everyone , i get this warning when i am trying to pop the screen ( i click on the back to the previous page button ) before the page loads ( the data comes from the server ) .

  • on android i get only this warning .
  • on ios i get the same warning and the app crashes.

image

any help please ?

Pass error to the error builders?

At the moment, PagingController.error is only used in a null check.
It'd be great if this value could be passed into the error builders, as it's cleaner than having to fetch it from the original source in the build function.

setState being called during Build

Hey I'm setting up a PagedListview that only has one item per page. I have several paged listviews that work fine but there's something odd about this one, i'm getting the following error on the NotifiyNewpage method:

Error
I/flutter ( 5572): ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
I/flutter ( 5572): The following assertion was thrown while dispatching notifications for
I/flutter ( 5572): CalendarGridPaginationService:
I/flutter ( 5572): setState() or markNeedsBuild() called during build.
I/flutter ( 5572): This AnimatedBuilder widget cannot be marked as needing to build because the framework is already in
I/flutter ( 5572): the process of building widgets.  A widget can be marked as needing to be built during the build
I/flutter ( 5572): phase only if one of its ancestors is currently building. This exception is allowed because the
I/flutter ( 5572): framework builds parent widgets before children, which means a dirty descendant will always be
I/flutter ( 5572): built. Otherwise, the framework might not visit this widget during this build phase.
I/flutter ( 5572): The widget on which setState() or markNeedsBuild() was called was:
I/flutter ( 5572):   AnimatedBuilder
I/flutter ( 5572): The widget which was currently being built when the offending call was made was:
I/flutter ( 5572):   SliverList
I/flutter ( 5572):
I/flutter ( 5572): When the exception was thrown, this was the stack:
I/flutter ( 5572): #0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4292:11)
I/flutter ( 5572): #1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4307:6)
I/flutter ( 5572): #2      State.setState (package:flutter/src/widgets/framework.dart:1264:14)
I/flutter ( 5572): #3      _AnimatedState._handleChange (package:flutter/src/widgets/transitions.dart:175:5)
I/flutter ( 5572): #4      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:226:25)
I/flutter ( 5572): #5      PagedDataSource.notifyNewPage (package:infinite_scroll_pagination/src/workers/paged_data_source.dart:129:5)
I/flutter ( 5572): #6      CalendarGridPaginationService.fetchItems (package:rvised/services/pagination/calendar_grid_pagination_service.dart:15:5)

I have tried replacing the PagedChildBuilderDelegate to just return a Container, same issue. when I replace the PagedListView with a normal ListView it works just fine.

I can of course prevent the crash by adding a isListingInProgress check but that (naturally) breaks the pagination:

@override
void fetchItems(int pageKey) async {

  //if (isListingInProgress) return;

  final newItems = [ DateUtils.getMonth(pageKey)];

  final hasFinished = newItems.length < _pageSize;
  final nextPageKey = hasFinished ? null : pageKey + newItems.length;
  notifyNewPage(newItems, nextPageKey);
}

One page containing 1 item is loaded, this item usually doesn't fill the list completely.
I have been staring at this for several days and it's obviously going to be something extremely stupid I missed. But I hope you can help out ;)

PagedListView implementation
@override
Widget build(BuildContext context) {
  return Column(
    children: <Widget>[
      Expanded(
        child: PagedListView<int, CalendarMonth>(
          invisibleItemsThreshold: 1,
          cacheExtent: (MediaQuery.of(context).size.width / DateTime.daysPerWeek) * 6,
          padding: listPadding ?? EdgeInsets.zero,
          dataSource: dataSource,
          builderDelegate: PagedChildBuilderDelegate(
            itemBuilder: (context, item, index) => _MonthView(
              month: item.month,
              items: item.items,
              monthBuilder: monthBuilder,
              dayBuilder: dayBuilder,
              filter: dayFilter,
            ),
          ),
        ),
      ),
    ],
  );
}

Can not find NoMoreItemsIndicator

@EdsonBueno , Let me start with thanks for sharing your great work with the rest of us, quick question, I'm using 2.2.3. I cannot find NoMoreItemsIndicator class introduced in (2.1.0), I would like to override all IndicatorBuilder so we can provide globalization.

Should NoMoreItemsIndicator be a child class of FirstPageExceptionIndicator?

Error with the restorationId

hi i got the following error when i use your component

.org/infinite_scroll_pagination-2.2.0/lib/src/ui/paged_grid_view.dart:65:11: Error: No named parameter with the name 'restorationId'.
restorationId: restorationId,

Scroll to index

hi, first of all, very happy to use this plugin and it is really easy to implement to my project. but i would like to know, is there a "scroll to index" functionality like after we click on the notification with list item id, i want to scroll my list to the list item.
Thanks in advance.

Prevent content disappearing on refresh()

On pullToRefresh I would like to leave content in infinite_scroll_pagination "as is" if there are no new items (new items appear on the top as in Instagram for example). I want content to be replaced by refresh only when the initial state changed. My point is that when using pullToRefresh first infinite_scroll_pagination removes all content (all items) leaving blank page with loading indicator and then after items are loaded it displays them again. Looks weird if those are exactly same items. Instead I would like to show loader over current content and replace content only if new items are available. Is there any way to achieve this in infinite_scroll_pagination?

Ideally if there was a method setPage() (in addition to appendPage() and appendLastPage()) which would just set current state of paging controller.

RefreshIndicator(
  onRefresh: () => Future.sync(
    // () => pagingController.refresh(), <- instead of this
    // do this ->
    () async {
      final result = await getLatestItems();
      if (/* custom logic to check if paging content should be replaced because new items are available */) {
        pagingController.setPage(result.items, result.nextCursor);
      }  
    }
  ),
  child: PagedListView<Cursor, ActivityDocument>(...),
);

version mismatch

infinite_scroll_pagination: ^2.3.0

The current Flutter SDK version is 1.21.0-6.0.pre.245.
Because app depends on infinite_scroll_pagination >=2.2.0+1which requires Flutter SDK version >=1.22.0 <2.0.0, version solving failed.

[Question] return Widgets as a Fake Items in a builder

In the firstPageProgressIndicatorBuilder and newPageProgressIndicatorBuilder, we can custom our widget to be shown. But how to show fake items with those builder ? For Eg. 8 Items for firstPageProgressIndicatorBuilder or 2 Items for newPageProgressIndicatorBuilder. The idea is I want to show the skeleton loader. It might be worked in the Listview but not in GridView.

Add item and change item

In sorted pagination, e.g. task list sorted alphabetically by name, how can I add a new item or change the name of the item?

Padding property causing scroll

The bottom padding property of the PagedListView causes loadings builder to be scrollable, but not the top padding.

child: PagedListView.separated( padding: const EdgeInsets.fromLTRB(15, 5, 15, 90), builderDelegate: ......, )

ScreenRecord-2021-01-19-11-57-56.2.1.mp4

Duplicate page requests are made when the PageController contains initial data

I'm using MobX to store data, and I cache the first page of it on startup. To load the pagination widget with initial data, I have this in my initState:

_pagingController.value = PagingState(
  nextPageKey: _store.nextPageOffset,
  itemList: _store.loadedItems,
  error: _store.errorMessage,
);

The problem is that the widget always requests the page at nextPageKey in its initState(), which we can see here.

This is an erranous duplicate request, as since there's data that's already loaded, the list item builder will also request more data (with the same key, but a different _fetchTriggerIndex).

I believe this can be fixed by simply checking if there's existing data in initState, and skipping the request accordingly.

I originally incorrectly identified the cause of this issue, oops! The old (incorrect) report is below.

I'm using MobX for state management, and I pre-download the first page of items when my app starts up.
As such, I provide a non-zero integer to the firstPageKey in my PaginController.

The problem is that regardless of this value, _lastFetchTriggerIndex is always set to zero when the first page loads, as we can see here.

As the page started with data, items are already being built. As a result of this, a page load is requested again, here.

This would normally be skipped, because _lastFetchTriggerIndex should be equal to the newFetchTriggerIndex. It's not, however, because it's zero instead of the firstPageKey initially.

This results in the page being requested twice.

When use this widget inside tab bar view, it gets refresh every time the tab is switch back

Let's say I have tab1, tab2, etc

Currently I only have two tabs but I think the problem is the same in three tabs or more.

So, when I switch from tab1 to tab2, then I go back from tab2 to tab1, the refresh mechanism is triggered in tab1... why? Memory related issue? Or is there a property I can control this behavior?

To my understanding, there's already a property addAutomaticKeepAlives... so, why would such things still happen?

Thanks in advance!

remove item

Hello, how do we delete an item after clicking the method?

PagedGridView doesn't wait for scroll end?

Hi @EdsonBueno ,
Does PagedGridView not wait for scroll to go till end of the screen? Or am I missing something?
Currently it is making API calls pagewise, but not waiting for next page call till I scroll till the end of 1st page.

This is my PagedGridView.
PagedGridView( pagingController: _pagingController, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 0.65, crossAxisSpacing: 15, mainAxisSpacing: 15, ), builderDelegate: PagedChildBuilderDelegate<Product>( itemBuilder: (context, item, index) => ChangeNotifierProvider.value( value: item, child: ProductCard( subcategoryId: widget.subcategoryId, ), ), ), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), ),

Future<void> _fetchPage(int pageKey) async { try { final newItems = await Provider.of<ProductsProvider>(context, listen: false) .fetchProducts(widget.subcategoryId, pageKey); final isLastPage = newItems.length < _pageSize; if (isLastPage) { _pagingController.appendLastPage(newItems); } else { final nextPageKey = pageKey + 1; _pagingController.appendPage(newItems, nextPageKey); } } catch (error) { _pagingController.error = error; } }

Force call on refresh.

When doing a search, if the API call takes time then only the first call to refresh() makes the loading appear and all the subsequent calls to refresh() are ignored until the error or the page is appended. In perfect case this works fine with debounce as in the search example, but if the API call is delayed then the search API call will get lost.
Is there any way to achieve it as of now?

SliverPadding

@EdsonBueno When I wrap PagedSliverList with SliverPadding to add some padding, the PagedSliverList ignore scrolling and fetch all pages infinitely
There is no other option to add padding

pagination happens even not scrolling

hi, thanks for this awesome package and that detailed and funny post about how to use it, but I have a problem that, when this CommentMessageList widget initState(come to life or visible to user), that network request(used to load data) happens couple times! (without user scrolling but to my understanding of the mechanism of how this package work, the data requesting should only happen when user scroll to a certain point of the list... right?

I don't know if it's the way how we 'turn page' break the underline pagination or anything... but that shouldn't happen, I guess...

Well, I have a list with length of 7, and the pagination in this case will be happening twice, right?

And this two network requesting happen all at once, once the user is entering the page containing this widget, and there's definitely no scrolling happened yet(because just enter the page.... and the data barely loaded...)

Why?

By the way, the way we 'turn page' is not to use pageNumber or anything that can be calculated, but to use the ts(a timestamp value) from the last element of the last list from the last request...

Why we 'turn page' in this way is because the list is dynamic, meaning each element have the possibility to be deleted... and when it delete, in the backend, there'll be a row of record missed, hence the pageNumber will be incorrect...

Not sure if it's how we paginate cause the problem...

And I paste the code below, hopefully you can help me a little bit here, thanks in advance!

class CommentMessageList extends StatefulWidget {
  @override
  _CommentMessageListState createState() => _CommentMessageListState();
}

class _CommentMessageListState extends State<CommentMessageList> {
  List<CommentMessage> _commentMessageList;

  int _commentMessageListTotal;

  String lastPageLastItemTs;

  final _pagingController = PagingController<String, CommentMessage>(
    // pageNumber: 1 (we call pageNumber while this package call it pageKey)
    firstPageKey: '',
  );

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

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

  Future<void> _getCommentMessageList(String ts) async {
    try {
      Response res = await request.getWithToken(api.getCommentMessage, arg: {
        'pageSize': '5',
        'ts': ts == '' ? null : ts,
      });

      final commentMessageListRaw = commentMessageListRawFromJson(res.body);

      _commentMessageListTotal =
          _commentMessageListTotal ?? commentMessageListRaw.data.total;

      final isLastPage =
          _pagingController.itemList?.length == _commentMessageListTotal;

      // //TODO: complete this error throwing logic later
      // if (commentMessageListRaw.success) {
      //   if (commentMessageListRaw.errorCode != '0') {
      //     throw Error();
      //   }
      // }

      print('total === $_commentMessageListTotal');
      print('length == ${_pagingController.itemList?.length}');

      if (isLastPage) {
        _pagingController.appendLastPage(commentMessageListRaw.data.list);
      } else {
        lastPageLastItemTs = _commentMessageListTotal == 0
            ? ''
            : commentMessageListRaw.data.list?.last?.ts;
        _pagingController.appendPage(
            commentMessageListRaw.data.list, lastPageLastItemTs);
      }
    } catch (error) {
      print(error);
      debugPrint(error);
      _pagingController.error = error;
    }
  }

  @override
  Widget build(BuildContext context) {
    return PagedListView(
      padding: EdgeInsets.only(top: 16),
      pagingController: _pagingController,
      builderDelegate: PagedChildBuilderDelegate<CommentMessage>(
        itemBuilder: (context, commentMessage, index) =>
            CommentMessageListItem(commentMessage: commentMessage),
        noItemsFoundIndicatorBuilder: (context) => PlaceholderMailboxFry(),
        newPageErrorIndicatorBuilder: (context) => Padding(
          padding: const EdgeInsets.all(16.0),
          child: Center(
            child: Text('Something wrong'),
          ),
        ),
        noMoreItemsIndicatorBuilder: (context) => Padding(
          padding: const EdgeInsets.all(16.0),
          child: Center(
            child: Text('Finished'),
          ),
        ),
      ),
    );
  }
}

Trying to Wrap Column ERROR

Your package is pretty awesome thanks for making this happen, but when I am trying to wrap with Column suddenly it is an error like this:

Code Sample

Column(
            children: [
              Container(
                child: PagedListView<int, dynamic>(
                  pagingController: _pagingController,
                  builderDelegate: PagedChildBuilderDelegate<dynamic>(
                      itemBuilder: (context, item, index) {
                    return CarListItemDefaultView(item);
                    return Container(
                      height: 200,
                      child: Text(item.name),
                    );
                  }),
                ),
              )
            ],
          ),

Error logs

════════ Exception caught by rendering library ═════════════════════════════════════════════════════
RenderBox was not laid out: RenderFlex#c7c17 relayoutBoundary=up2 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1785 pos 12: 'hasSize'

Handle dismissible?

Is there a way to handle dismissible for the widgets inside an infinite scroll? I'd like to remove the row without losing the user's place inside the current scroll.

I would think that somehow it would be removing that single item from inside the pagecontroller without losing the already "downloaded" items.

RenderViewport issue

I am trying to implement this package and currently stuck with the below exception. I would need your help on this to successfully release my app.

I/flutter (28888): The following assertion was thrown building NotificationListener<ScrollNotification>:
I/flutter (28888): A RenderViewport expected a child of type RenderSliver but received a child of type
I/flutter (28888): RenderRepaintBoundary.

The complete error log is given below at the end below.

This is the main screen which is based on CustomScrollView.

class CategoryView extends StatelessWidget {
  final ChannelModel category;

  CategoryView(this.category);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            title: Text(
              category.name,
              style: TextStyle(fontSize: 18.0),
            ),
          ),
          PostsList(category: category.slug),
        ],
      ),
    );
  }
}

Below is the list which will be used in the above main screen.

class PostsList extends StatefulWidget {
  final bool showOnlyFav;
  final bool showPopular;
  final String userId;
  final String label;
  final String category;
  final String favUserId;

  PostsList({
    this.showOnlyFav = false,
    this.showPopular = false,
    this.userId,
    this.category,
    this.label,
    this.favUserId,
  });

  @override
  _PostsListState createState() => _PostsListState();
}

class _PostsListState extends State<PostsList> {
  static const _pageSize = 20;
  final PagingController<int, PostModel> _pagingController =
      PagingController(firstPageKey: 0);

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

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

  Future<void> _fetchPage(int pageKey) async {
    try {
      final newItems = await FirestoreDatabase().postsStream(
          favUserId: widget.favUserId,
          category: widget.category,
          userId: widget.userId,
          label: widget.label,
          showPopular: widget.showPopular,
          showOnlyFav: widget.showOnlyFav);
      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) {
    return PagedListView<int, PostModel>(
      pagingController: _pagingController,
      builderDelegate: PagedChildBuilderDelegate<PostModel>(
        itemBuilder: (context, item, index) => SingleDesignWidget(item),
      ),
    );
  }
}

The full exception is below.

I/flutter (28888): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (28888): The following assertion was thrown building NotificationListener<ScrollNotification>:
I/flutter (28888): A RenderViewport expected a child of type RenderSliver but received a child of type
I/flutter (28888): RenderRepaintBoundary.
I/flutter (28888): RenderObjects expect specific types of children because they coordinate with their children during
I/flutter (28888): layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a
I/flutter (28888): RenderSliver does not understand the RenderBox layout protocol.
I/flutter (28888): 
I/flutter (28888): The RenderViewport that expected a RenderSliver child was created by:
I/flutter (28888):   Viewport ← IgnorePointer-[GlobalKey#7c030] ← Semantics ← _PointerListener ← Listener ←
I/flutter (28888):   _GestureSemantics ← RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#e85f2] ←
I/flutter (28888):   _PointerListener ← Listener ← _ScrollableScope ← _ScrollSemantics-[GlobalKey#c1f39] ←
I/flutter (28888):   RepaintBoundary ← ⋯
I/flutter (28888): 
I/flutter (28888): The RenderRepaintBoundary that did not match the expected child type was created by:
I/flutter (28888):   RepaintBoundary ← NotificationListener<ScrollNotification> ← GlowingOverscrollIndicator ←
I/flutter (28888):   Scrollable ← PagedListView<int, PostModel> ← PostsList ← Viewport ←
I/flutter (28888):   IgnorePointer-[GlobalKey#7c030] ← Semantics ← _PointerListener ← Listener ← _GestureSemantics ← ⋯
I/flutter (28888): 
I/flutter (28888): The relevant error-causing widget was:
I/flutter (28888):   PagedListView<int, PostModel> file:///D:/Flutter/womenly/lib/screens/posts/posts_list.dart:74:12
I/flutter (28888): 
I/flutter (28888): When the exception was thrown, this was the stack:
I/flutter (28888): #0      ContainerRenderObjectMixin.debugValidateChild.<anonymous closure> (package:flutter/src/rendering/object.dart:3123:9)
I/flutter (28888): #1      ContainerRenderObjectMixin.debugValidateChild (package:flutter/src/rendering/object.dart:3150:6)
I/flutter (28888): #2      MultiChildRenderObjectElement.insertRenderObjectChild (package:flutter/src/widgets/framework.dart:6191:25)
I/flutter (28888): #3      RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:5805:35)
I/flutter (28888): #4      RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5501:5)
I/flutter (28888): #5      SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6117:11)
I/flutter (28888): ...     Normal element mounting (37 frames)
I/flutter (28888): #42     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #43     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): #44     _ViewportElement.mount (package:flutter/src/widgets/viewport.dart:225:11)
I/flutter (28888): ...     Normal element mounting (127 frames)
I/flutter (28888): #171    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #172    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (103 frames)
I/flutter (28888): #275    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #276    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (208 frames)
I/flutter (28888): #484    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #485    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (70 frames)
I/flutter (28888): #555    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #556    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (210 frames)
I/flutter (28888): #766    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #767    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (156 frames)
I/flutter (28888): #923    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #924    Element.updateChild (package:flutter/src/widgets/framework.dart:3324:20)
I/flutter (28888): #925    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4652:16)
I/flutter (28888): #926    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
I/flutter (28888): #927    Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
I/flutter (28888): #928    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2730:33)
I/flutter (28888): #929    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:913:20)
I/flutter (28888): #930    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
I/flutter (28888): #931    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
I/flutter (28888): #932    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1055:9)
I/flutter (28888): #933    SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:864:7)
I/flutter (28888): (elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
I/flutter (28888): 
I/flutter (28888): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (28888): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (28888): The following assertion was thrown building GlowingOverscrollIndicator(axisDirection: down, show:
I/flutter (28888): both sides, Color(0xff2196f3), dependencies: [_EffectiveTickerMode], state:
I/flutter (28888): _GlowingOverscrollIndicatorState#88371(tickers: tracking 4 tickers)):
I/flutter (28888): A RenderViewport expected a child of type RenderSliver but received a child of type RenderErrorBox.
I/flutter (28888): RenderObjects expect specific types of children because they coordinate with their children during
I/flutter (28888): layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a
I/flutter (28888): RenderSliver does not understand the RenderBox layout protocol.
I/flutter (28888): 
I/flutter (28888): The RenderViewport that expected a RenderSliver child was created by:
I/flutter (28888):   Viewport ← IgnorePointer-[GlobalKey#7c030] ← Semantics ← _PointerListener ← Listener ←
I/flutter (28888):   _GestureSemantics ← RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#e85f2] ←
I/flutter (28888):   _PointerListener ← Listener ← _ScrollableScope ← _ScrollSemantics-[GlobalKey#c1f39] ←
I/flutter (28888):   RepaintBoundary ← ⋯
I/flutter (28888): 
I/flutter (28888): The RenderErrorBox that did not match the expected child type was created by:
I/flutter (28888):   ErrorWidget-[#77063] ← NotificationListener<ScrollNotification> ← GlowingOverscrollIndicator ←
I/flutter (28888):   Scrollable ← PagedListView<int, PostModel> ← PostsList ← Viewport ←
I/flutter (28888):   IgnorePointer-[GlobalKey#7c030] ← Semantics ← _PointerListener ← Listener ← _GestureSemantics ← ⋯
I/flutter (28888): 
I/flutter (28888): The relevant error-causing widget was:
I/flutter (28888):   PagedListView<int, PostModel> file:///D:/Flutter/womenly/lib/screens/posts/posts_list.dart:74:12
I/flutter (28888): 
I/flutter (28888): When the exception was thrown, this was the stack:
I/flutter (28888): #0      ContainerRenderObjectMixin.debugValidateChild.<anonymous closure> (package:flutter/src/rendering/object.dart:3123:9)
I/flutter (28888): #1      ContainerRenderObjectMixin.debugValidateChild (package:flutter/src/rendering/object.dart:3150:6)
I/flutter (28888): #2      MultiChildRenderObjectElement.insertRenderObjectChild (package:flutter/src/widgets/framework.dart:6191:25)
I/flutter (28888): #3      RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:5805:35)
I/flutter (28888): #4      RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5501:5)
I/flutter (28888): ...     Normal element mounting (37 frames)
I/flutter (28888): #41     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #42     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): #43     _ViewportElement.mount (package:flutter/src/widgets/viewport.dart:225:11)
I/flutter (28888): ...     Normal element mounting (127 frames)
I/flutter (28888): #170    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #171    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (103 frames)
I/flutter (28888): #274    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #275    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (208 frames)
I/flutter (28888): #483    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #484    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (70 frames)
I/flutter (28888): #554    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #555    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (210 frames)
I/flutter (28888): #765    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #766    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6236:32)
I/flutter (28888): ...     Normal element mounting (156 frames)
I/flutter (28888): #922    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
I/flutter (28888): #923    Element.updateChild (package:flutter/src/widgets/framework.dart:3324:20)
I/flutter (28888): #924    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4652:16)
I/flutter (28888): #925    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
I/flutter (28888): #926    Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
I/flutter (28888): #927    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2730:33)
I/flutter (28888): #928    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:913:20)
I/flutter (28888): #929    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
I/flutter (28888): #930    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
I/flutter (28888): #931    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1055:9)
I/flutter (28888): #932    SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:864:7)
I/flutter (28888): (elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
I/flutter (28888): 
I

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();
  }
}

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.

The getter 'iterator' was called on null.

Hi ,

i'm using mvc pattren here is snap of my code :

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

HomeController() {
pagingNearRestaurantsController.addPageRequestListener((pageKey) {
// _con.listenForOrders(pageKey);
// orderRepo.fetchPosts(orderRepo.nextUrl);
_fetchNearRestaurantsPage(pageKey);
});
}

Future _fetchNearRestaurantsPage(pageKey) async {

if(pageKey==0)
  newNearRestaurantsItems = await restaurantRepo.getNearRestaurants(deliveryAddress.value, deliveryAddress.value,null);
else
  newNearRestaurantsItems = await restaurantRepo.getNearRestaurants(deliveryAddress.value, deliveryAddress.value,restaurantRepo.nextUrl);

try{
  final isLastPage = newNearRestaurantsItems.length < _pageNearRestaurantsSize;
  if (isLastPage) {
    pagingNearRestaurantsController.appendLastPage(newNearRestaurantsItems);
  } else {
    final nextPageKey = pageKey + newNearRestaurantsItems.length;
    pagingNearRestaurantsController.appendPage(newNearRestaurantsItems, nextPageKey);
  }
} catch (error) {
  pagingNearRestaurantsController.error = error;
}

}

Future<List> getNearRestaurants(
Address myLocation, Address areaLocation,uri) async {

if(uri==null) {
uri = Helper.getUri('api/restaurants');
Map<String, dynamic> _queryParams = {};
SharedPreferences prefs = await SharedPreferences.getInstance();
Filter filter = Filter.fromJSON(
json.decode(
prefs.getString('filter') ?? new Filter("opened").toJson()));

if (!myLocation.isUnknown() && !areaLocation.isUnknown()) {
  _queryParams['myLon'] = myLocation.longitude.toString();
  _queryParams['myLat'] = myLocation.latitude.toString();
  _queryParams['areaLon'] = areaLocation.longitude.toString();
  _queryParams['areaLat'] = areaLocation.latitude.toString();
}
_queryParams['availability'] = filter.availability.toString();
uri = uri.replace(queryParameters: _queryParams);
uriFinal=uri;

}
else
uriFinal=uri;

http.Response response = await http.get(
    uriFinal );
var responseJson = json.decode(response.body);
var data = responseJson['data']['data'];

if (responseJson['data']['next_page_url'] != null) {
  nextUrl = responseJson['data']['next_page_url'];
}

return (data as List)
    .map((p) => Restaurant.fromJSON(p))
    .toList();

}

////
[VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: NoSuchMethodError: The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 new List.from (dart:core-patch/array_patch.dart:57:19)
#2 PagingController.notifyStatusListeners (package:infinite_scroll_pagination/src/core/paging_controller.dart:134:28)
#3 PagingController.value= (package:infinite_scroll_pagination/src/core/paging_controller.dart:175:7)
#4 PagingController.error= (package:infinite_scroll_pagination/src/core/paging_controller.dart:59:5)
#5 HomeController._fetchNearRestaurantsPage (package:foodlobby_client_app/src/controllers/home_controller.dart:72:39)

#6 new HomeController. (package:foodlobby_client_app/src/controllers/home_controller.dart:40:7)
#7 PagingController.notifyPageRequestListeners. (package:infinite_scroll_pagination/src/core/paging<…

Export FooterTile class

The FooterTile class can be quite useful to build custom widgets with, it'd be great if it was accessible to developers.

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?

Pages fetched all at once and each page two times

Hi,
I'm working on pagination for my app (Flutter for web) and I noticed two issues:

  • all pages are fetched at once, not on the scroll
  • every page is requested twice (_fetchPage is called two times for each pageKey)

What is interesting, the number of items as a result is correct, no duplications. So for end user it's not really visible, and still better than waiting for one huge request, but would be nice to get this working properly. Might it be different behavior for PagingController in web?

Code:

class IssuesBody extends StatefulWidget {
  const IssuesBody();

  @override
  _IssuesBodyState createState() => _IssuesBodyState();
}

class _IssuesBodyState extends State<IssuesBody> {
  static const int _pageSize = 15;
  final IssuesRepository _issuesRepository = locator<IssuesRepository>();

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

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

  Future<void> _fetchPage(int pageKey) async {
    try {
      final IssuesResponse issuesResponse = await _issuesRepository.fetchIssues(pageKey, _pageSize);
      final List<IssuesDetails> newItems = issuesResponse.results;
      final bool isLastPage = newItems.length < _pageSize;
      if (isLastPage) {
        _pagingController.appendLastPage(newItems);
      } else {
        final int nextPageKey = pageKey + 1;
        _pagingController.appendPage(newItems, nextPageKey);
      }
    } catch (error) {
      _pagingController.error = error;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        _buildIssuesHeader(),
        const SizedBox(height: 30),
        PagedListView<int, IssuesDetails>(
          shrinkWrap: true,
          pagingController: _pagingController,
          builderDelegate: PagedChildBuilderDelegate<IssuesDetails>(
            itemBuilder: (BuildContext context, IssuesDetails issuesBuilding, int index) {
              return IssuesBuildingCard(building: issuesBuilding);
            },
          ),
        ),
      ],
    );
  }

  Widget _buildIssuesHeader() {
    // not relevant, simple widget
  }

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

Can't build a widget dynamically in itemBuilder

Thanks for amazing plugin it works just fine as intended however I was trying to create a wrapper of it to reduce boilerplate code and faced TypeError when returning a custom widget in itemBuilder using callback.

Below code can help reproduce this error

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

typedef PagedListFetcher<T> = Future<List<T>> Function(int offset);

typedef PagedListWidgetBuilder<T> = Widget Function(
    BuildContext context, T item);

Future<List<String>> fetchData(int offset) async {
  await Future.delayed(Duration(seconds: 2));
  return List<String>.generate(10, (index) => '${index + offset}th item');
}

class PostsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Posts'),
      ),
      body: PagedList<String>(
        fetcher: (offset) {
          return fetchData(offset);
        },
        widgetBuilder: (context, item) {
          return Text(
            '$item',
          );
        },
      ),
    );
  }
}

/// Page list wrapper for Posts and Comments data.
class PagedList<T> extends StatefulWidget {
  /// This will build comment/post widget.
  final PagedListWidgetBuilder<T> widgetBuilder;

  /// This will fetch comment/post data at a time.
  final PagedListFetcher fetcher; //executor

  const PagedList({
    Key key,
    @required this.widgetBuilder,
    @required this.fetcher,
  }) : super(key: key);

  @override
  _PagedListState createState() => _PagedListState<T>();
}

class _PagedListState<T> extends State<PagedList> {
  static const _pageSize = 10;

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

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

  @override
  Widget build(BuildContext context) {
    return PagedListView<int, T>(
      pagingController: _pagingController,
      builderDelegate: PagedChildBuilderDelegate<T>(
        itemBuilder: (context, item, index) {
          //return Text(index.toString()); //THIS WORKS FINE
          return widget.widgetBuilder(context, item); //THIS THROWS ERROR
        },
      ),
    );
  }

  Future<void> _fetchPage(int pageKey) async {
    print('pageKey: $pageKey');
    final List<T> newData = await widget.fetcher(pageKey);
    print('newData: $newData');
    final isLastPage = newData.length < _pageSize;

    if (isLastPage) {
      _pagingController.appendLastPage(newData);
    } else {
      final nextPageKey = pageKey + newData.length;
      print('nextPageKey: $nextPageKey');
      _pagingController.appendPage(newData, nextPageKey);
    }
  }

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

Logs

Performing hot restart...
Syncing files to device Android SDK built for x86...
Restarted application in 4,283ms.
I/flutter ( 7403): pageKey: 0
I/flutter ( 7403): newData: [0th item, 1th item, 2th item, 3th item, 4th item, 5th item, 6th item, 7th item, 8th item, 9th item]
I/flutter ( 7403): nextPageKey: 10

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following _TypeError was thrown building:
type '(BuildContext, String) => Text' is not a subtype of type '(BuildContext, dynamic) => Widget'

When the exception was thrown, this was the stack: 
#0      _PagedListState.build.<anonymous closure> (package:test/pages/post/posts_page.dart:74:25)
#1      _PagedSliverBuilderState._buildListItemWidget (package:infinite_scroll_pagination/src/ui/paged_sliver_builder.dart:234:52)
#2      new AppendedSliverChildBuilderDelegate.<anonymous closure> (package:infinite_scroll_pagination/src/utils/appended_sliver_child_builder_delegate.dart:28:33)
#3      SliverChildBuilderDelegate.build (package:flutter/src/widgets/sliver.dart:449:22)
#4      SliverMultiBoxAdaptorElement._build (package:flutter/src/widgets/sliver.dart:1130:28)
...
════════════════════════════════════════════════════════════════════════════════════════════════════

Any help/fix/comment will be appreciated.

Question: Manipulate items

@EdsonBueno Thanks a lot for the awesome library, I love it!

We have appendPage and appendLastPage methods to add items to infinite scroll. I have a delete button, when press it, I want to delete an item, is it possible to manipulate items? how?

I don't want to call refresh() method , I just want to delete an item

many widget errors

Hi,

when i use PagedListView in body of Scaffold widget it works fine , but when i used it as an element in cloumn or parnet listview i get many errors like :

════════ Exception caught by rendering library ═════════════════════════════════════════════════════
BoxConstraints forces an infinite height.
The relevant error-causing widget was:
PagedListView<int, Food> file:///Users/hesham/StudioProjects/foodlobby_client/lib/src/pages/menu_list.dart:115:9
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════════════════════════
Null check operator used on a null value
The relevant error-causing widget was:
PagedListView<int, Food> file:///Users/hesham/StudioProjects/foodlobby_client/lib/src/pages/menu_list.dart:115:9
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════════════════════════
Null check operator used on a null value
The relevant error-causing widget was:
PagedListView<int, Food> file:///Users/hesham/StudioProjects/foodlobby_client/lib/src/pages/menu_list.dart:115:9
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════════════════════════
Null check operator used on a null value
The relevant error-causing widget was:
PagedListView<int, Food> file:///Users/hesham/StudioProjects/foodlobby_client/lib/src/pages/menu_list.dart:115:9
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════════════════════════
RenderBox was not laid out: RenderShrinkWrappingViewport#f8e22 relayoutBoundary=up18 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1785 pos 12: 'hasSize'
The relevant error-causing widget was:
PagedListView<int, Food> file:///Users/hesham/StudioProjects/foodlobby_client/lib/src/pages/menu_list.dart:115:9

=====

my code :

 @override
  Widget build(BuildContext context) {
return Scaffold(
  key: _con.scaffoldKey,
  drawer: DrawerWidget(),
  appBar: AppBar(
    backgroundColor: Colors.transparent,
    elevation: 0,
    centerTitle: true,
    title: Text(
      _con.foods.isNotEmpty && _con.foods[0].restaurantName != null
          ? _con.foods[0].restaurantName
          : '',
      overflow: TextOverflow.fade,
      softWrap: false,
      style: Theme.of(context)
          .textTheme
          .title
          .merge(TextStyle(letterSpacing: 0)),
    ),
    actions: <Widget>[
      ShoppingCartButtonWidget(
          iconColor: Theme.of(context).hintColor,
          labelColor: Theme.of(context).accentColor)
    ],
  ),
  floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
  body: ListView(
    shrinkWrap: true,
    padding: EdgeInsets.symmetric(vertical: 10),
      children: <Widget>[
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20),
          child: SearchBarWidget(),
        ),
        ListTile(
          dense: true,
          contentPadding:
              EdgeInsets.symmetric(horizontal: 20, vertical: 10),
          leading: Icon(
            Icons.trending_up,
            color: Theme.of(context).hintColor,
          ),
          title: Text(
            S.of(context).trending_this_week,
            style: Theme.of(context).textTheme.display1,
          ),
          subtitle: Text(
            S.of(context).double_click_on_the_food_to_add_it_to_the,
            style: Theme.of(context)
                .textTheme
                .caption
                .merge(TextStyle(fontSize: 11)),
          ),
        ),
        FoodsCarouselWidget(
            heroTag: 'menu_trending_food', restaurantController: _con),
        ListTile(
          dense: true,
          contentPadding:
              EdgeInsets.symmetric(horizontal: 20, vertical: 10),
          leading: Icon(
            Icons.list,
            color: Theme.of(context).hintColor,
          ),
          title: Text(
            S.of(context).all_menu,
            style: Theme.of(context).textTheme.display1,
          ),
          subtitle: Text(
            S.of(context).longpress_on_the_food_to_add_suplements,
            style: Theme.of(context)
                .textTheme
                .caption
                .merge(TextStyle(fontSize: 11)),
          ),
        ),
    
    PagedListView<int, Food>.separated(
          scrollDirection: Axis.vertical,
      primary: false,
      shrinkWrap: true,
      pagingController: _con.pagingFoodsController,
          builderDelegate: PagedChildBuilderDelegate<Food>(
            itemBuilder: (context, item, index) {
              return FoodItemWidget(
                  heroTag: "menu_list",
                  food: item);
            },
            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),
        )
      ],
    ));

}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.