【问题标题】:How to show loading indicator when scrolled to end of the list in flutter如何在颤动中滚动到列表末尾时显示加载指示器
【发布时间】:2020-06-24 06:49:42
【问题描述】:

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

Main.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


    【解决方案1】:

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

    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(
             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,
                                     ),
                                ));
                              }
    )
    }
    }
    

    【讨论】:

      【解决方案2】:

      您可以通过使用Stack 小部件并将CircularProgressIndicatorListView 重叠来实现此目的。查看下面的代码以获取简化示例:

      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);
          };
        }
      }
      

      【讨论】:

      • 我按照你说的做了更改,但是那个圆形指示器显示在中心并不断加载所有列表。我想在我们滚动到列表末尾时添加列表,并在获取列表时显示指示器。
      • 但这正是最后一段代码所做的。当您开始获取时,_loading 变为 true,并且 CircularProgressIndicator 显示。完成后,_loading 变为 false,CircularProgressIndicator 被替换并隐藏。
      • 我的意思是不滚动到列表的末尾就可以获取数据。我不想在不滚动到列表末尾的情况下获取。
      猜你喜欢
      • 1970-01-01
      • 2020-08-27
      • 2013-10-14
      • 2017-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多