FutureBuilder загружает данные API только один раз - PullRequest
0 голосов
/ 20 февраля 2020

Я вызвал тип записи api для асинхронной загрузки данных в ListView с помощью FutureBuilder, но он вызывался только один раз, я хочу отобразить бесконечную загрузку данных в моем ListView.

Не хватает их, чтобы добавить некоторые свойства FutureBuilder или ListView.

Может кто-нибудь помочь мне решить эту проблему, я новичок в трепетании.

Я использую виджет с состоянием для достижения этой функции.

Пожалуйста, обратитесь код ниже,

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

Ответы [ 2 ]

1 голос
/ 20 февраля 2020

Вы можете использовать Stream вместо Future. Это обобщенный пример c с кешем и scrollController, который выбирает следующие элементы, когда пользователь находится на нижней странице:

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
            ),
        }
      ),
    );
  }
}
0 голосов
/ 21 февраля 2020

Асинхронно загружать данные с помощью 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(),
                ),
              ),

            ],

          ),

        )

    );
  }
}
...