advanced_pagination 0.2.0
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.
PagedLayoutBuilderand 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),
);
Load‑more error retry footer #
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: iftrue, loads the first page after build.enableRefresh: enables pull-to-refresh inPagedListView.reverse: reverses scroll direction (useful for chat UIs).preloadOffset: how close to the end beforefetchNext()triggers.enableScrollPrefetch: enables earlyprefetchNext().prefetchOffset: how early prefetch starts.loadingBuilder: custom loader widget (defaults toCircularProgressIndicator).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.