Supercharge Pagination in Flutter with Super Paging

Published on by Flutter News Hub

Supercharge Pagination in Flutter with Super Paging

Super Paging is a comprehensive Flutter package that streamlines data management, caching, and pagination. With configurable widgets, error handling, and extensive customization options, it simplifies the task of creating seamless and performant pagination experiences.

Features

  • In-Memory Caching: Reduces network requests and improves performance by intelligently caching frequently accessed data.
  • Configurable Widgets: Customize the look and feel of your pagination with built-in widgets like PagingListView and BidirectionalPagingListView.
  • Error Handling: Gracefully handles potential errors during data loading and retrieval, ensuring a smooth user experience.
  • Flexible Configuration: Tailor Super Paging's behavior to your specific needs by adjusting parameters like initial keys, page sizes, and caching strategies.
  • Extensive Documentation: Clear and comprehensive documentation makes it easy for developers of all levels to implement Super Paging effectively.

Installation

Add the following to your pubspec.yaml:

dependencies: super_paging: ^[version]

Usage

1. Create a PagingSource:

This class defines the logic for loading and retrieving data.

class RickAndMortySource extends PagingSource {
  RickAndMortyApi api;
  RickAndMortySource();

  @override
  Future load(PagingConfig config, int key) async {
    try {
      final characters = await api.getCharacters(page: key);
      return LoadResult.page(nextKey: key + 1, items: characters);
    } catch (e) {
      return LoadResult.error(e);
    }
  }
}

2. Create a Pager Instance:

The Pager coordinates the data loading and provides the data to the UI.

final pager = Pager(
  initialKey: 1,
  config: const PagingConfig(
    pageSize: 20,
    initialLoadSize: 60,
  ),
  pagingSourceFactory: () => RickAndMortySource(api: RickAndMortyApi()),
);

3. Integrate with UI:

The PagingListView widget renders the data returned by the pager.

PagingListView(
  pager: pager,
  itemBuilder: (BuildContext context, int index) {
    final item = pager.items.elementAt(index);
    return ListTile(
      title: Text(item.name),
      subtitle: Text(item.species),
      trailing: Text('# ${item.id}'),
      leading: CircleAvatar(backgroundImage: NetworkImage(item.image)),
    );
  },
  emptyBuilder: (BuildContext context) {
    return const Center(
      child: Text('No characters found'),
    );
  },
  errorBuilder: (BuildContext context, Object? error) {
    return Center(child: Text('$error'));
  },
  loadingBuilder: (BuildContext context) {
    return const Center(
      child: CircularProgressIndicator.adaptive(),
    );
  },
);

Customization

Pager:

Pager(
  // Defines the initial key to use for the first load.
  initialKey: null,

  // Configuration for pagination behavior.
  config: PagingConfig(
    // Defines the number of items to load in a single page.
    pageSize: 20,

    // Defines the number of items to load in the first page.
    initialLoadSize: 60,

    // Defines how far from the edge of loaded content an access
    // must be to trigger further loading.
    prefetchIndex: 3,

    // Defines the maximum number of items to keep in memory before
    // pages should be dropped.
    maxSize: null,
  ),

  // Defines the initial state to use for the first load.
  initialState: PagingState.initial(),

  // Defines the source from which to load the paginated data.
  pagingSourceFactory: () => MyPagingSource(),
);

PagingListView:

PagingListView(
  // Defines the pager to use for loading data.
  pager: myPager,

  // Defines the builder that is called to build items in the ListView.
  itemBuilder: (context, index) {
    final item = myPager.valueList.elementAt(index);
    return ListTile(
      title: Text(item),
    );
  },

  // Defines the builder that is called to build the empty state of the list.
  emptyBuilder: (context) {
    return const Center(
      child: Text('No items found'),
    );
  },

  // Defines the builder that is called to build the error state of the list.
  errorBuilder: (context, error) {
    return Center(child: Text('Error: $error'));
  },

  // Defines the builder that is called to build the loading state of the list.
  loadingBuilder: (context) {
    return const Center(
      child: CircularProgressIndicator.adaptive(),
    );
  },

  // Defines the builder that is called to build the prepend state of the list.
  prependStateBuilder: (context, state, pager) {
    // Return a widget based on the state. For example, a button to load the previous page.
    // Use the [pager] instance to call [pager.load()] or [pager.retry] based on the state.
  },

  // Defines the builder that is called to build the append state of the list.
  appendStateBuilder: (context, state, pager) {
    // Return a widget based on the state. For example, a button to load the next page.
    // Use the [pager] instance to call [pager.load()] or [pager.retry] based on the state.
  },
);
Flutter News Hub