如何在flutter中滚动到列表末尾时显示加载指示器

问题描述 投票:0回答:2

我正在使用 future 从服务器加载数据,并使用列表视图生成器在列表视图中显示数据,并在滚动到列表末尾时添加新列表,但在新的项目列表时无法显示加载指示器正在加载。我在下面附上了我的代码。我已经尝试过该软件包loadmore但没有运气。

主.dart

class Herbs extends StatefulWidget {
  final String title;
  Herbs(this.title);

  @override
  _HerbsState createState() => new _HerbsState();
}

class _HerbsState extends State<Herbs> {
  ScrollController _scrollController = new ScrollController();
  var data;
  var cname;
  String gcm = '';
  List pages = [];

  @override
  void initState() {
    super.initState();
    fetchPost(gcm);
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        print('Page reached end of page');
        setState(() {
          Text('Loading');
        });
        fetchPost(gcm);
      }
    });
  }

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

  @override
  Widget build(BuildContext context) {
    cname = widget.title;
    var hgt = MediaQuery.of(context).size.width * 0.65;
    var wid = MediaQuery.of(context).size.height * 0.58;
    return new Scaffold(
      appBar: AppBar(
        title: Align(
          alignment: Alignment(-0.2, 0.3),
          child: Text(
            cname,
          ),
        ),
      ),
      body: Center(
        child: FutureBuilder<Herbslist>(
          future: fetchPost(gcm),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return Scrollbar(
                child: ListView.builder(
                  controller: _scrollController,
                  shrinkWrap: true,
                  itemCount: pages == null ? 0 : pages.length,
                  itemBuilder: (BuildContext context, int index) {
                    gcm = snapshot.data.herbslistContinue.gcmcontinue;
                    var img = pages[index].thumbnail.source;
                    return GestureDetector(
                        onTap: () {
                          Navigator.push(
                              context,
                              MaterialPageRoute(
                                builder: (context) => Detailpage(
                                  pages[index].title,
                                ),
                              ));
                        },
                        child: Card(
                            child: Column(
                          children: <Widget>[
                            CachedNetworkImage(
                              placeholder: (context, url) => Image.asset(
                                'images/image.png',
                                height: hgt,
                                width: wid,
                                fit: BoxFit.fill,
                              ),
                              imageUrl: img,
                              height: hgt,
                              width: wid,
                              fit: BoxFit.fill,
                            ),
                            ListTile(
                              title: Text(pages[index].title, style: TextStyle(fontWeight: FontWeight.bold),),
                            )
                          ],
                        )));
                  },
                ),
              );
            } else {
              return Center(
                child: CircularProgressIndicator(),
              );
            }
          },
        ),
      ),
    );
  }

  Future<Herbslist> fetchPost(gcm) async {
    String url =
        'https://eample.org/api.php?action=query&gcmtitle=Category:$cname&pilimit=max&prop=pageimages&pithumbsize=200&generator=categorymembers&format=json&gcmcontinue=$gcm';
    final response = await http.get(url);
    print(url);
    if (response.statusCode == 200) {
      data = Herbslist.fromJson(json.decode(response.body));
      pages.addAll(data.query.pages.values);
      return data;
    } else {
      throw (e) {
        print("Exception thrown: $e");
        Exception(e);
      };
    }
  }
}
listview flutter lazy-loading
2个回答
9
投票

以下是对我有用的方法(其他人的情况可能有所不同)

class _HerbsState extends State<Herbs> {
  bool _loading = false;

@override
  void initState() {
    super.initState();
    fetchPost(gcm);
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        print('Page reached end of page');
        setState(() {});
        fetchPost(gcm);
      }
    });
  }

Widget build(BuildContext context) {
    return Scaffold(
        body: ListView.builder(
            controller: _scrollController,
            shrinkWrap: true,
            itemCount: pages == null ? 0 : pages.length + 1, //add +1 here
            itemBuilder: (BuildContext context, int index) {
              if (index == pages.length) {
                _loading =
                    true; // declare the boolean and return loading indicator
                return Center(
                    child: Container(
                  child: SpinKitThreeBounce(
                    color: Colors.green,
                    size: 30,
                  ),
                ));
              }
            }));
  }
}

1
投票

您可以通过使用

Stack
小部件并将
CircularProgressIndicator
ListView
重叠来完成此操作。检查下面的代码以获得简化示例:

class LoadingOnScroll60619794 extends StatefulWidget {
  @override
  _LoadingOnScroll60619794State createState() => _LoadingOnScroll60619794State();
}

class _LoadingOnScroll60619794State extends State<LoadingOnScroll60619794> {
  bool _loading = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.refresh),
            onPressed: runLoading
          ),
        ],
      ),
      body: Stack(
        children: <Widget>[
          ListView(
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text('item 1'),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text('item 1'),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text('item 1'),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text('item 1'),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text('item 1'),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text('item 1'),
              ),
            ],
          ),
          _loading
            ? Center(
              child: CircularProgressIndicator(),
            )
            : SizedBox(width: 0, height: 0,)
        ],
      ),
    );
  }

  void runLoading(){
    setState(() {
      _loading = true;
    });
    Timer(Duration(milliseconds: 1500), (){
      setState(() {
        _loading = false;
      });
    });
  }
}

如果您修改代码以在每次获取数据时更改 _loading 变量,您将获得相同的效果。就像下面的例子:

Future<Herbslist> fetchPost(gcm) async {
  setState(() {
    _loading = true;
  });
  String url =
    'https://eample.org/api.php?action=query&gcmtitle=Category:$cname&pilimit=max&prop=pageimages&pithumbsize=200&generator=categorymembers&format=json&gcmcontinue=$gcm';
  final response = await http.get(url);
  print(url);
  if (response.statusCode == 200) {
    data = Herbslist.fromJson(json.decode(response.body));
    pages.addAll(data.query.pages.values);
    setState(() {
      _loading = false;
    });
    return data;
  } else {
    setState(() {
      _loading = false;
    });
    throw (e) {
      print("Exception thrown: $e");
      Exception(e);
    };
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.