Do somthings

DoSomthings logo
scrolling pagination gif(Dosomthings)

Hi, guys I hope you all are well so in this article we learn to crate RefreshIndicator, scrolling pagination with the dynamic data from the server. First, we create a simple scrolling pagination with static values then we go further with dynamic data.

A simple workaround for the infinite scroll (Pagination) in Flutter ListView!

We face many requirements in our daily application development for infinite scrolling (pagination)in ListView and we are like. We start creating ListView then create a list of widgets and set scroll listener and set error or failure scenarios and then lastly, stop the pagination when data loading is completed.

What if I tell you that you have one widget in which you just need to pass your callback with data that will be called when the user reaches the end of the list?

Step 1: Implement pagination from scratch

Open main.dart file and implement these codes in it. normally this code navigates into separate classes where we write and execute the scrolling pagination code.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'Scrolling Pagination/scrolling_pagination.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays:[]).then(
        (_) => runApp(MyApp()),
  );
 //  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    return new MaterialApp(
        debugShowCheckedModeBanner: false,
        home:  ScrollingPagination(),
    );
  }
}

Step 2: Create and Open ScrollingPagination.dart file

First you create A-List of 15 items that we display inside ListView.builder.

 List<String> items = List.generate(15,

     ((index) => 'Item ${index+1}')

 );

once you reach the bottom of the list then we load more data so simply one more item to list view itemCount: items.length + 1 .

ListView.builder(
          controller: controller,
          padding: EdgeInsets.all(8.0),
          itemCount: items.length+1,
          itemBuilder: (context, index) {
            final item = items[index];
            return ListTile(title: Text(item),);
            
          }),

then apply the if else condition when the data not the last so the simple list other vise show the else condition inside the else condition we put CircularProgressIndicator.

ListView.builder(
         
          padding: EdgeInsets.all(8.0),
          itemCount: items.length+1,
          itemBuilder: (context, index) {
            if(index < items.length){
              final item = items[index];
              return ListTile(title: Text(item),);
            }else{
              return Padding(padding: EdgeInsets.all(32),
                child: Center(child: CircularProgressIndicator(),),
              );
            }


          }),

next we create ScrollController and add into ListView.builder. and initState we listen to the scrollcontroller and check if they have reach the end of the list then we fetch more data. and also we dispose the ScrollController.

final controller = ScrollController();
  
  @override
  void initState() {
    super.initState();

    controller.addListener(() {
      if(controller.position.maxScrollExtent == controller.offset){
        fetch();
      }
    });
  }

  Future fetch() async{

    setState(() {
      items.addAll(['Item A','Item B','Item C','Item D']);
    });

  }

Full Code:

import 'package:flutter/material.dart';

class ScrollingPagination extends StatefulWidget {
  const ScrollingPagination({Key? key}) : super(key: key);

  @override
  State<ScrollingPagination> createState() => _ScrollingPaginationState();
}

class _ScrollingPaginationState extends State<ScrollingPagination> {
  List<String> items = List.generate(15, ((index) => 'Item ${index + 1}'));

  final controller = ScrollController();

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

    controller.addListener(() {
      if (controller.position.maxScrollExtent == controller.offset) {
        fetch();
      }
    });
  }

  Future fetch() async {
    setState(() {
      items.addAll(['Item A', 'Item B', 'Item C', 'Item D']);
    });
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Scrolling Pagination'),
        centerTitle: true,
      ),
      body: ListView.builder(
          controller: controller,
          padding: EdgeInsets.all(8.0),
          itemCount: items.length + 1,
          itemBuilder: (context, index) {
            if (index < items.length) {
              final item = items[index];
              return ListTile(
                title: Text(item),
              );
            } else {
              return Padding(
                padding: EdgeInsets.all(32),
                child: Center(
                  child: CircularProgressIndicator(),
                ),
              );
            }
          }),
    );
  }
}
scrolling pagination1 gif(Dosomthings)

Scrolling Pagination with Dynamic data(API)

it’s very simple like previews one but add some more code like this you use HTTP package(http: ^0.13.5) to load some item from the server when the response code success then we get response body into newItems which add to the current item list

dependencies:
  http: ^0.13.5
 Future fetch() async{

 
    final url = Uri.parse('https://jsonplaceholder.typicode.com/posts');
    final responce = await http.get(url);

    if(responce.statusCode == 200){
      final List newItems = jsonDecode(responce.body);

      setState(() {

        page++;
        isLoading = false;

        if(newItems.length < limit){
          hasMore = false;
        }

        items.addAll(newItems.map<String>((item){

          final number = item['id'];
       

          return 'Item $number';
        }).toList());
      });

    }

let go to the website from this URL we get the data in from of Json in this time we only use the id

ListView.builder(
            
              controller: controller,
              padding: EdgeInsets.all(8.0),
              itemCount: items.length + 1,
              itemBuilder: (context, index) {
                if(index < items.length){
                  final item = items[index];
                  return ListTile(

                    title:  Text(item),

                  );
                }
                else{
                  return Padding(
                    padding: EdgeInsets.symmetric(vertical: 32),
                    child: Center(
                      child: hasMore
                          ? CircularProgressIndicator()
                          : Text("No more data"),
                    ),
                  );
                }
              }),

therefore we map over the item from each item extract the id and return text item which number. nwext you set the limit like page 1 define the first 25 data and if page 2 is define other 25 data and so on

  final url = Uri.parse('https://jsonplaceholder.typicode.com/posts?_limit=$limit&_page=$page');

and finally wrap around the ListView into RefreshIndicator in with the refresh method

RefreshIndicator(
          onRefresh: refresh,
          child: ListView.builder(

              controller: controller,
              padding: EdgeInsets.all(8.0),
              itemCount: items.length + 1,
              itemBuilder: (context, index) {
                if(index < items.length){
                  final item = items[index];
                  return ListTile(

                    title:  Text(item),

                  );
                }
                else{
                  return Padding(
                    padding: EdgeInsets.symmetric(vertical: 32),
                    child: Center(
                      child: hasMore
                          ? CircularProgressIndicator()
                          : Text("No more data"),
                    ),
                  );
                }
              }),
        )

Full Code:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class ScrollingPagination extends StatefulWidget {
  const ScrollingPagination({Key? key}) : super(key: key);

  @override
  State<ScrollingPagination> createState() => _ScrollingPaginationState();
}

class _ScrollingPaginationState extends State<ScrollingPagination> {
  final controller = ScrollController();
  List<String> items = [];
  bool hasMore = true;
  int page = 1;
  bool isLoading = false;

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

    fetch();

    controller.addListener(() {
      if (controller.position.maxScrollExtent == controller.offset) {
        fetch();
      }
    });
  }

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

  Future fetch() async {
    if (isLoading) return;
    isLoading = true;

    const limit = 25;

    final url = Uri.parse(
        'https://jsonplaceholder.typicode.com/posts?_limit=$limit&_page=$page');
    final responce = await http.get(url);

    if (responce.statusCode == 200) {
      final List newItems = jsonDecode(responce.body);

      setState(() {
        page++;
        isLoading = false;

        if (newItems.length < limit) {
          hasMore = false;
        }

        items.addAll(newItems.map<String>((item) {
          final number = item['id'];

          return 'Item $number';
        }).toList());
      });
    }
  }

  Future refresh() async {
    setState(() {
      isLoading = false;
      hasMore = true;
      page = 0;
      items.clear();
    });
    fetch();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Scrolling Pagination'),
          centerTitle: true,
        ),
        body: RefreshIndicator(
          onRefresh: refresh,
          child: ListView.builder(
              controller: controller,
              padding: EdgeInsets.all(8.0),
              itemCount: items.length + 1,
              itemBuilder: (context, index) {
                if (index < items.length) {
                  final item = items[index];
                  return ListTile(
                    title: Text(item),
                  );
                } else {
                  return Padding(
                    padding: EdgeInsets.symmetric(vertical: 32),
                    child: Center(
                      child: hasMore
                          ? CircularProgressIndicator()
                          : Text("No more data"),
                    ),
                  );
                }
              }),
        ));
  }
}

Conclusion :

For the major requirement of Flutter pagination ListView, Flutter Pagination Helper will be a more suitable option and for more specification, you can go with the first option.

And thanks for reading this blog, for detail info please click here

For more blogs please click here.

So pls follow the above step and if you have any issues or suggestions you can leave your message in the comment section I will try to solve this.