0

I've called post type api to load data asynchronously on ListView using FutureBuilder but it called only once, I want to display infinite data loading on my ListView.

Is their I missing to add some properties of FutureBuilder or ListView.

Can anyone help me solved this issue, I'm new to flutter.

I'm using stateful widget to achieve this functionality.

Please refer below code,

import 'package:flutter/material.dart';
import 'package:testlistviewlazyload/Utils.dart';
import 'package:testlistviewlazyload/ServiceManager.dart';
import 'package:testlistviewlazyload/Constant.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';

class ClassHome extends StatefulWidget {
  @override
  stateClassHome createState() => stateClassHome();
}

class stateClassHome extends State<ClassHome> {

  bool isLoading = false;

  List<dynamic> arrayFoodList = List<dynamic>();

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


  Future<List<dynamic>> funcLoadMore() async{

      var dicArguments = {'restaurant_id': '3',
        'menu_id': '0',
        'offset': '0'
      };

     final dictResponse = await ServiceManager().callWebservice(
          enumMethodType.POST, ConstantApi.keyRestaurantMenuFoodList,
          dicArguments, {
        'Authorization':
        await Utils().funcGetSession(ConstantSession.keyAuthToken)
      }, 'tagRestaurantMenuFoodList');

      if (dictResponse['error'] == false) {
        if (dictResponse['mainResponse']['error'] == false) {

          return dictResponse['mainResponse']['data']['food_items']
          as List<dynamic>;

        } else {

          Utils()
              .funcDisplayAlertView(
              '', "${dictResponse['message']}", context);

        }
      } else {
        Utils().funcDisplayAlertView(
            '', "${dictResponse['message']}", context);
      }

  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
        appBar: AppBar(title: Text('hello')),
        body: Container(
          color: Colors.pink[50],

          child: Column(

            children: <Widget>[

              Expanded(

                child: FutureBuilder<List<dynamic>>(
                     future: funcLoadMore(), // a previously-obtained Future<String> or null
                   builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {

                     List<dynamic> arrayTest = snapshot.data ?? [];

                      return Scrollbar(

                          child: ListView.builder(

                            itemCount: arrayTest.length,

                            itemBuilder: (BuildContext context, int index) {
                              return ListTile(
                                title: Text(arrayTest[index]['name']),
                              );
                            },

                          )
                      );
                     },
                ),


              ),

              Container(
                height: isLoading ? 50.0 : 0,
                color: Colors.white,
                child: Center(
                  child: new CircularProgressIndicator(),
                ),
              ),

            ],

          ),

        )

    );
  }
}

enter image description here

Dharini
  • 700
  • 7
  • 20
  • check out this link you will get the idea : https://codinginfinite.com/flutter-future-builder-pagination/ or check out this link :https://flutter-academy.com/flutter-listview-infinite-scrolling/ – Sagar Acharya Feb 20 '20 at 13:02

2 Answers2

4

You can use a Stream instead of Future. This is an generic example, with a cache and a scrollController which fetches the next items when user is at the bottom page :

class _PageState extends State<Page> {
  int _count = 10;
  int _limit = 0;

  bool isLoading = false;

  List<Item> _cachedItems = List.from([]);

  StreamController<List<Item>> _streamController =
      StreamController<List<Item>>();
  StreamSink<List<Item>> get itemsSink => _streamController.sink;
  Stream<List<Item>> get itemsStream => _streamController.stream;

  ScrollController _scrollController = ScrollController();

  Future<void> _addItems() async {
    final params = {'count': '$_count', 'limit': '$_limit'};
    try {
      isLoading = true;
      // Fetch newItems with http
      isLoading = false;
      _cachedItems.addAll(newItems);
      itemsSink.add(_cachedItems);
      _limit += 10;
    } catch (e) {
      itemsSink.addError(e);
    }
  }

  _scrollListener() {
    if (_scrollController.offset >=
            _scrollController.position.maxScrollExtent &&
        !_scrollController.position.outOfRange &&
        !isLoading) {
      _addItems();
    }
  }

  @override
  void initState() {
    _scrollController.addListener(_scrollListener);
    super.initState();
  }

  @override
  void didChangeDependencies() {
    if (_cachedItems.isEmpty) _addItems();
    super.didChangeDependencies();
  }

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

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<Item>>(
        stream: itemsStream,
        builder: (context, snapshot) {
            ListView(
               controller: _scrollController,
               /// Build here your ListView
            ),
        }
      ),
    );
  }
}
Augustin R
  • 7,089
  • 3
  • 26
  • 54
  • thanks for your reply I use ScrollController from your code & it helps me to solved my issue – Dharini Feb 21 '20 at 06:47
  • @Dharini you're welcome. If the answer solved your problem you should [accept it](https://stackoverflow.com/help/someone-answers). – Augustin R Feb 21 '20 at 06:54
0

It's so easy to load data asynchronously using ScrollController,

import 'package:flutter/material.dart';
import 'package:testlistviewlazyload/Utils.dart';
import 'package:testlistviewlazyload/ServiceManager.dart';
import 'package:testlistviewlazyload/Constant.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';

class ClassHome extends StatefulWidget {
  @override
  stateClassHome createState() => stateClassHome();
}

class stateClassHome extends State<ClassHome> {

  bool isLoading = false;
  ScrollController scrollController = ScrollController();
  List<dynamic> arrayFoodList = List<dynamic>();
  int varLoadedRecordsCount = 0;
  int varTotalRecords = 18;

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

    funcLoadMore();

    scrollController.addListener((){

      print('scroll controller called');

      if(scrollController.position.maxScrollExtent == scrollController.offset){

        if (varLoadedRecordsCount < varTotalRecords) {
          funcLoadMore();
        }
      }
    });
  }

void funcLoadMore() async{

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

      var dicArguments = {'restaurant_id': '3',
        'menu_id': '0',
        'offset': '${varLoadedRecordsCount}'
      };

     final dictResponse = await ServiceManager().callWebservice(
          enumMethodType.POST, ConstantApi.keyRestaurantMenuFoodList,
          dicArguments, {
        'Authorization':
        await Utils().funcGetSession(ConstantSession.keyAuthToken)
      }, 'tagRestaurantMenuFoodList');

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


    if (dictResponse['error'] == false) {
        if (dictResponse['mainResponse']['error'] == false) {

          print('response came');

          arrayFoodList.addAll(dictResponse['mainResponse']['data']['food_items']
          as List<dynamic>);

          varLoadedRecordsCount += arrayFoodList.length;

//          return dictResponse['mainResponse']['data']['food_items']
//          as List<dynamic>;

        } else {

          Utils()
              .funcDisplayAlertView(
              '', "${dictResponse['message']}", context);

        }
      } else {
        Utils().funcDisplayAlertView(
            '', "${dictResponse['message']}", context);
      }
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
        appBar: AppBar(title: Text('hello')),
        body: Container(
          color: Colors.pink[50],

          child: Column(

            children: <Widget>[

              Expanded(

                child: Scrollbar(

                    child: ListView.builder(

                      controller: scrollController,

                      itemCount: arrayFoodList.length,

                      itemBuilder: (BuildContext context, int index) {
                        return ListTile(
                          title: Text('${arrayFoodList[index]['name']}'),
                        );
                      },

                    )
                ),
              ),

              Container(
                height: isLoading ? 50.0 : 0,
                color: Colors.white,
                child: Center(
                  child: new CircularProgressIndicator(),
                ),
              ),

            ],

          ),

        )

    );
  }
}
Dharini
  • 700
  • 7
  • 20