Load More Pagination

load_more_pagination Extensible and highly customizable package to help you lazily load and display small chunks of items as the user scrolls down the screen. ✨

It's support any type of list view builder with endless scrolling pagination, lazy loading pagination, progressive loading pagination, etc.

Very smooth animations supporting Android, iOS & WebApp, DesktopApp.

Show Cases

alert2

Why?

We build this package because we wanted to:

  • have a complete pagination handling package with list view.
  • user able to refresh the page on end of listview.
  • set isFinish bool true if pagination count is ended.
  • Endless scrolling pagination.

Installation

Create a new project with the command

flutter create MyApp

Add

load_more_pagination: ...

to your pubspec.yaml of your flutter project. OR run

flutter pub add load_more_pagination

in your project's root directory.

In your library add the following import:

import 'package:load_more_pagination/load_more_pagination.dart';

For help getting started with Flutter, view the online documentation.

Usage

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Pagination Demo',
      theme: ThemeData(
        primarySwatch: Colors.red,
        platform: TargetPlatform.iOS,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({
    Key? key,

  }) : super(key: key);


  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  List<int> productList = [];
  bool isFinishLoadMore = false;

  @override
  void initState() {
    super.initState();
  }

  void initiateList() {
    productList.addAll(List.generate(10, (v) => v));
    setState(() {});
  }

  Future<bool> _loadMoreData() async {
    await Future.delayed(const Duration(seconds: 2));
    initiateList();
    if(productList.length>=30){
      isFinishLoadMore = true;
    }
    return true;
  }

  Future<void> _refresh() async {
    await Future.delayed(const Duration(seconds: 2));
    productList.clear();
    isFinishLoadMore = false;
    initiateList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Load More List"),
      ),
      body: RefreshIndicator(
        onRefresh: _refresh,
        child: LoadMorePagination(
          isFinish: isFinishLoadMore,
          onLoadMorePagination: _loadMoreData,
          loaderColor: Colors.green,
          whenEmptyLoad: true,
          delegate: const DefaultLoadMorePaginationDelegate(),
          textBuilder: DefaultLoadMorePaginationTextBuilder.english,
          child: ListView.builder(
            itemBuilder: (BuildContext context, int index) {
              return ListTile(
                title: Text('Product ${index+1}'),
                subtitle: const Text('Subtitle'),
              );
            },
            itemCount: productList.length,
          ),
        ),
      ),
    );
  }


}

Usage With GetX State Management

class OrdersNotificationController extends GetxController {
  Repository repository = Repository();
  RxList<OrderListModel> myOrdersList = <OrderListModel>[].obs;
  RxBool isFinishLoadMore = false.obs;
  RxBool isOrdersListLoading = true.obs;
  RxInt pageNumber = 1.obs;

  Future<bool> loadMore() async {
    await Future.delayed(const Duration(seconds: 0, milliseconds: 2000));
    await getOrdersList(shouldShowLoader: false);
    return true;
  }

  getOrdersList({bool shouldShowLoader = true, bool isPageRefresh = false}) async {
    try {
      String qParams = "pageSize=20&current=${pageNumber.value}";
      if (shouldShowLoader) isOrdersListLoading(true);
      List<dynamic>? response =
      await repository.getApiCall(url: "order/list?$qParams");
      if (isPageRefresh) myOrdersList.clear();
      if (response != null && response.isNotEmpty) {
        for (var element in response) {
          myOrdersList.add(OrderListModel.fromJson(element));
        }
        pageNumber.value += 1;
      } else {
        /// Changing isFinishLoadMore flag true when no more data available in pagination api.
        isFinishLoadMore(true);
      }
      isOrdersListLoading(false);
    } catch (e, stackTrace) {
      isOrdersListLoading(false);
    }
  }
}


class MyOrdersScreen extends StatefulWidget {
  const MyOrdersScreen({Key? key}) : super(key: key);
  @override
  State<MyOrdersScreen> createState() => _MyOrdersScreenState();
}

class _MyOrdersScreenState extends State<MyOrdersScreen> {
  /// find orders notification controller.
  final OrdersNotificationController _ordersNC = Get.find();

  @override
  void initState() {
  WidgetsBinding.instance.addPostFrameCallback((Duration time) => init());
  super.initState();
  }

  init() {
  bool isLogin = CommonLogics.checkUserLogin();
  if (isLogin) {
  _ordersNC.isFinishLoadMore(false);
  _ordersNC.pageNumber(1);
  _ordersNC.getOrdersList(shouldShowLoader: false, isPageRefresh: true);
  }
  }

  @override
  Widget build(BuildContext context) {
  return Scaffold(
  backgroundColor: CommonColors.appBgColor,
  body: Obx(() {
  return _ordersNC.isOrdersListLoading.value
  ? const Center(
  child: CircularProgressIndicator(
  color: CommonColors.appColor,
  ),
  )
      : ScrollConfiguration(
  behavior: const ScrollBehavior().copyWith(overscroll: false),
  child: RefreshIndicator(
  onRefresh: () async {
  _ordersNC.isFinishLoadMore(false);
  _ordersNC.pageNumber(1);
  await _ordersNC.getOrdersList(
  shouldShowLoader: false, isPageRefresh: true);
  return;
  },
  child: _ordersNC.myOrdersList.isNotEmpty
  ? LoadMorePagination(
  isFinish: _ordersNC.isFinishLoadMore.value,
  onLoadMorePagination: _ordersNC.loadMore,
  loaderColor: Colors.green,
  textBuilder: DefaultLoadMoreTextBuilder.english,
  child: ListView.builder(
  shrinkWrap: true,
  itemCount: _ordersNC.myOrdersList.length,
  itemBuilder: (context, index) {
  return GestureDetector(
  onTap: () {
  Get.to(() => OrderDetailsScreen(
  orderId: _ordersNC
      .myOrdersList[index]
      .orderItemId,
  ));
  },
  child: OrderTileWidget(
  orderListItem:
  _ordersNC.myOrdersList[index],
  ));
  }))
      : const NoDataScreen(),
  ),
  );
  }));
  }
}


Constructor

Basic

Parameter Default Description Required
child - ListView widget as a child. true
onLoadMorePagination - On load function for handling pagination. true
loaderColor - Bottom CircularProgressIndicator loader color. true
isFinish false is Finish book for handling load more end functionality. false

Libraries

load_more_pagination
Documentation