FutureBuilder仅加载一次API数据

时间:2020-02-20 12:29:27

标签: listview flutter dart statefulwidget

我已经调用post类型的api,以使用FutureBuilder在ListView上异步加载数据,但它只调用了一次,我想在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 个答案:

答案 0 :(得分:3)

您可以使用Stream代替Future。这是一个通用示例,带有一个缓存和一个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 ), } ), ); } } 会提取下一个项目:

{{1}}

答案 1 :(得分:0)

使用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(),
                ),
              ),

            ],

          ),

        )

    );
  }
}