Search code examples
flutterdart

Flutter How to make paging at Future<void>


I have data for 100 items coming from my API server and the data is fine with no problem with it, but I'm trying to make it show 20 items every time I get to the end of the list but it keeps loading without stopping that's my code.

  Widget build(BuildContext context) {
    return Center(
      child: NotificationListener<ScrollNotification>(
        onNotification: (ScrollNotification scrollInfo) {
          if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent &&
              hasMore) {
            fetchItems();
          }
          return true;
        },
        child: FutureBuilder<void>(
          future: fetchItems(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const Center(child: CircularProgressIndicator());
            } else if (snapshot.hasError) {
              return Center(child: Text('Error: ${snapshot.error}'));
            } else if (categoyItems == null || categoyItems!.isEmpty) {
              return const Center(child: Text('No states available'));
            } else {
              return GridView.custom(
                shrinkWrap: true,
                padding: const EdgeInsets.symmetric(vertical: 10),
                gridDelegate: SliverStairedGridDelegate(
                  mainAxisSpacing: 6,
                  crossAxisSpacing: 8,
                  pattern: [
                    const StairedGridTile(0.53, 0.8),
                    const StairedGridTile(0.470, 0.8),
                    const StairedGridTile(0.470, 0.8),
                    const StairedGridTile(0.53, 0.8),
                  ],
                ),
                childrenDelegate: SliverChildBuilderDelegate(
                  childCount: categoyItems!.length + (hasMore ? 1 : 0),
                  (context, index) {
                    if (index == categoyItems?.length) {
                      return const Center(child: CircularProgressIndicator());
                    }
                    final item = categoyItems![index];
                    return Container(....);
                  },
                ),
              );
            }
          },
        ),
      ),
    );
  }

and my function that get items from my API server

  List<CategoryItems>? categoyItems = [];
  int offset = 0;
  bool isLoading = false;
  bool hasMore = true;
  int totalCount = 0;
  bool hasData = false;

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

  Future<void> fetchItems() async {
    if (isLoading) return;

    setState(() {
      isLoading = true;
    });

    try {
      PaginatedCategoryItems paginatedItems = await AppMethods()
          .fetchCategoryItems(widget.type!, widget.state!, offset);

        setState(() {
          categoyItems!.addAll(paginatedItems.items);
          offset += paginatedItems.items.length;
          totalCount = paginatedItems.totalCount;
          isLoading = false;
          hasMore = categoyItems!.length < totalCount;
          hasData = true;
        });
      
    } catch (err) {
      if (kDebugMode) {
        print(err);
      }
      setState(() {
        isLoading = false;
      });
    }
  }

can someone help me, please?


Solution

  • try this Infinite_scroll_pagination

    and this is example code

    handleFetchMeme() in controller should return in paginate model like this model

    import 'package:freezed_annotation/freezed_annotation.dart';
    
    import '../meme_enitity/meme.entity.dart';
    
    part 'meme_pagination.entity.freezed.dart';
    part 'meme_pagination.entity.g.dart';
    
    @freezed
    class MemePaginationEntity with _$MemePaginationEntity {
      const factory MemePaginationEntity({
        @Default(0) num page,
        @Default(0) num perPage,
        @Default([]) List<MemeEntity> memeList,
      }) = _MemePaginationEntity;
    
      factory MemePaginationEntity.fromJson(Map<String, Object?> json)
          => _$MemePaginationEntityFromJson(json);
    }
    

    Example GetXController

    import 'package:get/get.dart';
    import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
    
    import '../../../domain/model/meme_enitity/meme.entity.dart';
    
    class PlaygroundPageController extends GetxController {
      @override
      void onInit() {
        pagingController.addPageRequestListener((pageKey) {
          handleGetMemeList(page: pageKey);
        });
        super.onInit();
      }
    
      final pagingController = PagingController<int, MemeEntity>(firstPageKey: 1);
    
      Future<void> handleGetMemeList({required int page}) async {
        try {
          final res = handleFetchMeme(page: page, perPage: 10);
          if (res.memeList.length < 10) {
            pagingController.appendLastPage(res.memeList);
          } else {
            pagingController.appendPage(res.memeList, ++page);
          }
        } catch (err) {
         pagingController.error = err;
        }
      }
    }
    

    Widget

    class PlaygroundPage extends StatelessWidget {
      const PlaygroundPage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return GetBuilder<PlaygroundPageController>(
          global: false,
          init: PlaygroundPageController(),
          builder: (controller) => Scaffold(
            backgroundColor: Colors.grey[200],
            appBar: CustomAppBar(
              backgroundColor: Colors.grey[500],
              title: '',
            ),
            body: Column(
              children: [
                PagedListView(
                  pagingController: controller.pagingController,
                  builderDelegate: PagedChildBuilderDelegate<MemeEntity>(
                    itemBuilder: (context, item, index) {
                      return Container(
                         child : Text(item.memeName)
                       ); // Your Widget
                    },
                  ),
                )
              ],
            ),
          ),
        );
      }
    }