advanced_pagination 0.2.0 copy "advanced_pagination: ^0.2.0" to clipboard
advanced_pagination: ^0.2.0 copied to clipboard

Controller-first pagination for Flutter with page/offset/cursor support, list/grid/sliver widgets, cache + prefetch, and customizable states.

Advanced Pagination - Flutter #

A controller-first pagination package for Flutter with page/offset/cursor support, clean widgets, cache + prefetch, and customizable loading/empty/error UI.

Features #

  • Page, offset, and cursor-based pagination.
  • PagedListView, PagedGridView, and sliver variants.
  • List separators and reverse pagination support.
  • Load‑more error retry footer (default or custom).
  • Sliver empty/error builders for fully custom states.
  • Scroll prefetch to load ahead of the viewport.
  • Cache manager with stale-while-revalidate support.
  • PagedLayoutBuilder and per-widget builders for custom states.

Installation #

Add to your pubspec.yaml:

dependencies:
  advanced_pagination: ^0.2.0

Then run:

flutter pub get

Quick Start #

1) Create a controller #

final controller = PaginationController.pageBased(
  firstPageKey: 1,
  pageSize: 20,
  fetchPage: (request) async {
    final page = request.pageKey ?? 1;
    final items = await api.fetchPage(page, request.pageSize);

    return PageResult(
      items: items,
      hasNext: page < 10,
      hasPrevious: page > 1,
    );
  },
);

2) Render a list #

PagedListView<int, Article>(
  controller: controller,
  itemBuilder: (context, item, index) => ArticleTile(item),
);

Controller Types #

Page-based #

final controller = PaginationController.pageBased(
  firstPageKey: 1,
  pageSize: 20,
  fetchPage: (request) async {
    final page = request.pageKey ?? 1;
    final items = await api.fetchPage(page, request.pageSize);

    return PageResult(
      items: items,
      hasNext: page < 10,
      hasPrevious: page > 1,
    );
  },
);

Offset-based #

final controller = PaginationController.offsetBased(
  initialOffset: 0,
  pageSize: 20,
  fetchPage: (request) async {
    final offset = request.pageKey ?? 0;
    final items = await api.fetchOffset(offset, request.pageSize);

    return PageResult(
      items: items,
      hasNext: items.isNotEmpty,
      hasPrevious: offset > 0,
    );
  },
);

Cursor-based #

final controller = PaginationController.cursorBased<String, Article>(
  initialCursor: "0",
  pageSize: 20,
  fetchPage: (request) async {
    final result = await api.fetchCursor(request.pageKey, request.pageSize);

    return PageResult(
      items: result.items,
      hasNext: result.nextCursor != null,
      hasPrevious: result.prevCursor != null,
      nextKey: result.nextCursor,
      prevKey: result.prevCursor,
    );
  },
);

Widgets #

PagedGridView #

PagedGridView<int, Article>(
  controller: controller,
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
    mainAxisSpacing: 8,
    crossAxisSpacing: 8,
  ),
  itemBuilder: (context, item, index) => ArticleTile(item),
);

PagedListView with separators + reverse #

PagedListView<int, Article>(
  controller: controller,
  reverse: true,
  separatorBuilder: (context, index) => const Divider(height: 1),
  itemBuilder: (context, item, index) => ArticleTile(item),
);

Sliver list/grid #

CustomScrollView(
  // Use reverse: true here if you want a reversed sliver list/grid.
  slivers: [
    const SliverAppBar(title: Text("Sliver Grid")),
    PagedSliverGrid<int, Article>(
      controller: controller,
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        childAspectRatio: 1.6,
      ),
      itemBuilder: (context, item, index) => ArticleTile(item),
    ),
  ],
);

Sliver empty / error builders #

PagedSliverList<int, Article>(
  controller: controller,
  emptyBuilder: (_) => const Center(child: Text("No items")),
  errorBuilder: (_, error) => const Center(child: Text("Load failed")),
  itemBuilder: (context, item, index) => ArticleTile(item),
);

Custom States #

PagedLayoutBuilder #

PagedLayoutBuilder<int, Article>(
  controller: controller,
  loadingBuilder: (_) => const Center(child: CircularProgressIndicator()),
  emptyBuilder: (_) => const Center(child: Text("No items")),
  errorBuilder: (_, error) => const Center(child: Text("Something went wrong")),
  builder: (context, state) {
    return PagedListView<int, Article>(
      controller: controller,
      itemBuilder: (context, item, index) => ArticleTile(item),
    );
  },
);

Per-widget builders #

PagedListView<int, Article>(
  controller: controller,
  loadingBuilder: (_) => const CircularProgressIndicator(),
  statusBuilder: (context, status) {
    if (status == PaginationStatus.error) {
      return const Center(child: Text("Oops"));
    }
    return const SizedBox.shrink();
  },
  itemBuilder: (context, item, index) => ArticleTile(item),
);
PagedListView<int, Article>(
  controller: controller,
  loadMoreErrorBuilder: (context, error) {
    return Center(
      child: TextButton(
        onPressed: () => controller.retry(),
        child: const Text("Retry loading more"),
      ),
    );
  },
  itemBuilder: (context, item, index) => ArticleTile(item),
);

Scroll Prefetch #

PagedListView<int, Article>(
  controller: controller,
  enableScrollPrefetch: true,
  prefetchOffset: 700,
  preloadOffset: 200,
  itemBuilder: (context, item, index) => ArticleTile(item),
);

Cache + Stale-While-Revalidate #

final cache = MemoryPaginationCacheManager<int, Article>(maxEntries: 10);

final controller = PaginationController.pageBased(
  firstPageKey: 1,
  pageSize: 20,
  fetchPage: (request) async { /* ... */ },
  cacheManager: cache,
  cacheKey: "articles-feed",
  cachePolicy: const PaginationCachePolicy(
    maxAge: Duration(minutes: 10),
    staleWhileRevalidate: true,
  ),
);

Parameters (Most Used) #

  • autoLoad: if true, loads the first page after build.
  • enableRefresh: enables pull-to-refresh in PagedListView.
  • reverse: reverses scroll direction (useful for chat UIs).
  • preloadOffset: how close to the end before fetchNext() triggers.
  • enableScrollPrefetch: enables early prefetchNext().
  • prefetchOffset: how early prefetch starts.
  • loadingBuilder: custom loader widget (defaults to CircularProgressIndicator).
  • separatorBuilder: adds separators between list items.
  • loadMoreErrorBuilder: custom footer when loading more fails.
  • emptyBuilder / errorBuilder: customize sliver empty/error states.

Controller API #

  • refresh(): reload from start.
  • fetchNext(): append next page.
  • fetchPrevious(): prepend previous page.
  • prefetchNext(): silent prefetch (no loader).
  • prefetchPrevious(): silent prefetch in the previous direction.
  • retry(): repeat last failed request.
  • cancel(): cancel active request.

Quick FAQ #

You can read the Quick-FAQ here: https://github.com/patoliavishal/flutter_advanced_pagination/wiki/Quick-FAQ

Running the Example App #

The example is a full Flutter app with android/ and ios/ folders.

cd example
flutter pub get
flutter run

For iOS on macOS, run flutter run and allow Xcode to handle signing if prompted.

Additional Information #

Pull requests and feedback are welcome. If you encounter any issues, please open a GitHub issue and include a minimal reproducible example.

1
likes
150
points
62
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Controller-first pagination for Flutter with page/offset/cursor support, list/grid/sliver widgets, cache + prefetch, and customizable states.

Repository (GitHub)
View/report issues

Topics

#pagination #infinite-scroll #lazy-loading #load-more #pull-to-refresh

License

MIT (license)

Dependencies

flutter

More

Packages that depend on advanced_pagination