flutter_pagination_kit

A pure, zero-dependency pagination toolkit that handles all 6 Grid/List/Sliver/Horizontal layouts out-of-the-box without forcing you to use Bloc, Riverpod, or any specific state management.

pub package likes pub points CI


flutter_pagination_kit demo flutter_pagination_kit demo 1 flutter_pagination_kit demo 2

Why this package?

If you've ever tried to implement pagination in your app, you know it's a hassle. You have to manage scroll controllers, loading states, error handling, pull-to-refresh, and deduplicating API requests.

This package solves all of that with a clean, un-opinionated API:

  • Batteries Included for All Layouts: Comes with ready-to-use widgets for ListView, GridView, horizontal variants, and raw Sliver equivalents for advanced CustomScrollView implementations.
  • Architecture Agnostic: Doesn't care if you use Provider, Riverpod, Bloc, GetX, or just setState. It simply works with your async functions.
  • Production-Grade Error Handling: Built-in safeguards against duplicate API calls, scroll-bounce thrashing, and infinite retry loops.
  • Completely Customizable: Provides sensible default UI for loading, empty, error, and no-more-data states out of the box, but allows you to override 100% of the UI builders with your own custom widgets.

Getting Started

Add the package to your pubspec.yaml:

dependencies:
  flutter_pagination_kit: ^0.1.0

Basic Usage

1. Create a Controller

Initialize a PaginationController by providing a fetchPage callback. This function will be called automatically when the list needs more data.

final _controller = PaginationController<Product>(
  fetchPage: (int page) async {
    // Replace with your actual API call. 
    // Return a PaginationResult with the new items and whether more pages exist.
    final items = await myRepository.fetchProducts(page: page, limit: 20);
    return PaginationResult(
      items: items,
      hasMore: items.length == 20,
    );
  },
);

2. Choose your Widget

Pick the widget that matches your layout needs. Pass it the controller and an itemBuilder.

PaginatedListView<Product>(
  controller: _controller,
  itemBuilder: (context, product, index) {
    return ListTile(
      title: Text(product.name),
      subtitle: Text('\$${product.price}'),
    );
  },
)

Don't forget to dispose the controller when your view is destroyed:

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

Advanced Usage

Slivers

If you need to place a paginated list alongside other scrollable elements (like headers, sticky search bars, or other lists), use the Sliver variants inside a CustomScrollView.

Important: To trigger pagination, you must wrap your CustomScrollView with a PaginationScrollListener.

RefreshIndicator(
  onRefresh: _controller.refresh, // Optional: Adds pull-to-refresh
  child: PaginationScrollListener(
    onLoadMore: _controller.loadNextPage,
    child: CustomScrollView(
      physics: const AlwaysScrollableScrollPhysics(), // Required for RefreshIndicator
      slivers: [
        const SliverAppBar(
          title: Text('My Awesome App'),
          floating: true,
        ),
        PaginatedSliverGrid<Product>(
          controller: _controller,
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
          ),
          itemBuilder: (context, product, index) {
            return ProductCard(product: product);
          },
        ),
      ],
    ),
  ),
)

Customizing States

Every paginated widget allows you to fully override the UI for every possible state:

PaginatedListView<Product>(
  controller: _controller,
  itemBuilder: (context, product, index) => MyItem(product),
  
  // Optional customizations:
  initialLoadingBuilder: (context) => const MyShimmerList(),
  emptyBuilder: (context) => const MyEmptyStateWidget(),
  errorBuilder: (context, error, retry) => MyErrorWidget(error, retry),
  loadingMoreBuilder: (context) => const CircularProgressIndicator(),
  noMoreDataBuilder: (context) => const Text('You reached the end!'),
)

Available Widgets

  • PaginatedListView - Standard vertical list.
  • PaginatedGridView - Standard vertical grid.
  • PaginatedHorizontalList - Horizontal scrolling list.
  • PaginatedHorizontalGrid - Horizontal scrolling grid (creates rows).
  • PaginatedSliverList - Sliver vertical list for CustomScrollView.
  • PaginatedSliverGrid - Sliver vertical grid for CustomScrollView.