Load more option in flutter ListView

Viewed 3705

I want to fetch all the infinite list view data in parts, means Initially it load 10 data item and on scroll more it should fetch next 10 items. I am fetching data from my Laravel api and in my Laravel api endpoint there is not option for per_page, so Please help me to integrate load more option of list view data. Here is my List data.

List<Category> _categoryList = List<Category>();
  CategoryService _categoryService = CategoryService();

  bool isLoading = true;

  @override
  void initState() {
    super.initState();
    _getAllCategories();
  }
  _getAllCategories() async {
    var categories = await _categoryService.getCategories();
    var result = json.decode(categories.body);
    result['data'].forEach((data) {
      var model = Category();
      model.id = data["id"];
      model.name = data["categoryName"];
      model.icon = data["categoryIcon"];
      setState(() {
        _categoryList.add(model);
        isLoading = false;
      });
    });
  }

And I am fetching all data in simple ListTile.

child: ListView.builder(
        itemCount: //_categoryList.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: _categoryList.name
          );
        },
      ),
3 Answers

So I have a trick and I am using it in my project. What we need here is to load more data when we are at the end of the list. So to do that we can use the ListView.builder() only:


child: ListView.builder(
       itemCount: _categoryList.length + 1,
       itemBuilder: (context, index) {
         if(index == _categoryList.length){
          // loadMore();
          // return Loading();         
          }
         return ListTile(
            title: _categoryList.name
          );
       }),

So what we are doing is that we have set _categoryList.length + 1 to the itemCount. If _categoryList.length was 10 then we will have 11 items in the ListView and the index range will be 0 - 10. So inside the builder, we are checking that the index is equals to _categoryList.length which is 10. If the index is equals to the length of _categoryList.length, then we are at the end of the List and we can simply call some functions to load more data from Api or to show a loading widget.

I guess I got your question right, in this way you can simply lazy load data when user gets to the end of the List without using any third party libraries.

This process called pagination. Laravel provides a function for it check Pagination in Laravel

For example

$users = DB::table('users')->paginate(15);// 15 is limit per page

And check it too Paging lib in flutter dev.

I have created a sample to load more data using web service You can see this example and you can implement for you json data.

https://android-pratap.blogspot.com/2018/12/flutter-infinite-listview-using.html

import 'package:akeepo/randomuser_infinitelist.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,

      ),
      home: InfiniteUsersList(),

   

    );
  }
}




import 'dart:async';
import 'dart:convert';

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

class InfiniteUsersList extends StatefulWidget {
  static String tag = 'users-page';

  @override
  State<StatefulWidget> createState() {
    return new _InfiniteUsersListState();
  }
}

class _InfiniteUsersListState extends State<InfiniteUsersList> {
  List<User> users = new List<User>();
  ScrollController _scrollController = new ScrollController();
  bool isPerformingRequest = false;
  int pageNumber = 0;

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

    // Loading initial data or first request to get the data
    _getMoreData();

    // Loading data after scroll reaches end of the list
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        _getMoreData();
      }
    });
  }

  // to show progressbar while loading data in background
  Widget _buildProgressIndicator() {
    return new Padding(
      padding: const EdgeInsets.all(8.0),
      child: new Center(
        child: new Opacity(
          opacity: isPerformingRequest ? 1.0 : 0.0,
          child: new CircularProgressIndicator(),
        ),
      ),
    );
  }

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

  // Webservice request to load 20 users data using paging
  Future<List<User>> _getUsers() async {
    List<User> users = new List<User>();
    setState(() {
      pageNumber++;
    });

    String url =
        "https://api.randomuser.me/?page=$pageNumber&results=20&seed=abc";
    print(url);

    var response = await http.get(url);
    var jsonData = json.decode(response.body);

    print(jsonData);

    var usersData = jsonData["results"];
    for (var user in usersData) {
      User newUser = User(user["name"]["first"] + user["name"]["last"],
          user["email"], user["picture"]["large"], user["phone"]);
      users.add(newUser);
    }

    return users;
  }

  _getMoreData() async {
    if (!isPerformingRequest) {
      setState(() {
        isPerformingRequest = true;
      });
      List<User> newEntries = await _getUsers(); //returns empty list
      if (newEntries.isEmpty) {
        double edge = 50.0;
        double offsetFromBottom = _scrollController.position.maxScrollExtent -
            _scrollController.position.pixels;
        if (offsetFromBottom < edge) {
          _scrollController.animateTo(
              _scrollController.offset - (edge - offsetFromBottom),
              duration: new Duration(milliseconds: 500),
              curve: Curves.easeOut);
        }
      }
      setState(() {
        users.addAll(newEntries);
        isPerformingRequest = false;
      });
    }
  }

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text('Users',
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.bold))),
      body: Container(
          child: ListView.builder(
              shrinkWrap: true,
              controller: _scrollController,
              itemCount: users.length + 1,
              itemBuilder: (BuildContext context, int index) {
                if (index == users.length) {
                  return _buildProgressIndicator();
                } else {
                  return ListTile(
                    onTap: () {
                      Navigator.push(
                          context,
                          new MaterialPageRoute(
                              builder: (context) =>
                                  UserDetailPage(users[index])));
                    },
                    title: Text(users[index].fullName),
                    subtitle: Text(users[index].mobileNumber),
                    leading: CircleAvatar(
                        backgroundImage: NetworkImage(users[index].imageUrl)),
                  );
                }
              })),
    );
  }
}

class User {
  final String fullName;

  final String email;

  final String imageUrl;

  final String mobileNumber;

  User(this.fullName, this.email, this.imageUrl, this.mobileNumber);
}

// User Detail Page

class UserDetailPage extends StatelessWidget {
  final User user;

  UserDetailPage(this.user);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("User Details"),
      ),
      body: Center(
        child: Text(
          user.fullName,
          style: TextStyle(fontSize: 35.0),
        ),
      ),
    );
  }
}
Related