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

Listview 在颤振中滚动到列表末尾时如何显示加载指示器,listview,flutter,lazy-loading,Listview,Flutter,Lazy Loading,我使用future从服务器加载数据,使用listview builder在列表视图中显示数据,并在滚动到列表末尾时添加新列表,但在加载新项目列表时,我无法显示加载指示器。我在下面附上了我的代码。我试过这个包裹,但运气不好 主飞镖 class Herbs extends StatefulWidget { final String title; Herbs(this.title); @override _HerbsState createState() => new _Her

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

主飞镖

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);
      };
    }
  }
}
类扩展StatefulWidget{
最后的字符串标题;
草药(本标题);
@凌驾
_HerbsState createState()=>new_Herbstate();
}
类_herbstate扩展状态{
ScrollController_ScrollController=新的ScrollController();
var数据;
var-cname;
字符串gcm='';
列表页=[];
@凌驾
void initState(){
super.initState();
fetchPost(gcm);
_scrollController.addListener((){
如果(_scrollController.position.pixels==
_scrollController.position.maxScrollExtent){
打印(“页面到达页面末尾”);
设置状态(){
文本(“加载”);
});
fetchPost(gcm);
}
});
}
@凌驾
无效处置(){
_scrollController.dispose();
super.dispose();
}
@凌驾
小部件构建(构建上下文){
cname=widget.title;
var hgt=MediaQuery.of(context).size.width*0.65;
var wid=MediaQuery.of(context).size.height*0.58;
归还新脚手架(
appBar:appBar(
标题:对齐(
对齐:对齐(-0.2,0.3),
子:文本(
cname,
),
),
),
正文:中(
孩子:未来建设者(
未来:fetchPost(gcm),
生成器:(上下文,快照){
if(snapshot.hasData){
返回滚动条(
子项:ListView.builder(
控制器:\ u滚动控制器,
收缩膜:对,
itemCount:pages==null?0:pages.length,
itemBuilder:(构建上下文,int索引){
gcm=snapshot.data.herbslitcontinue.gcmcontinue;
var img=pages[index].thumbnail.source;
返回手势检测器(
onTap:(){
导航器。推(
上下文
材料路线(
生成器:(上下文)=>Detailpage(
页[索引]。标题,
),
));
},
孩子:卡片(
子:列(
儿童:[
CachedNetworkImage(
占位符:(上下文,url)=>Image.asset(
“images/image.png”,
高度:hgt,
宽度:wid,
fit:BoxFit.fill,
),
imageUrl:img,
高度:hgt,
宽度:wid,
fit:BoxFit.fill,
),
列表砖(
标题:文本(页面[索引]。标题,样式:TextStyle(fontWeight:fontWeight.bold),
)
],
)));
},
),
);
}否则{
返回中心(
子对象:CircularProgressIndicator(),
);
}
},
),
),
);
}
未来回迁(gcm)异步{
字符串url=
'https://eample.org/api.php?action=query&gcmtitle=Category:$cname&pilimit=max&prop=pageimages&pitumbsize=200&generator=categorymembers&format=json&gcmcontinue=$gcm';
最终响应=等待http.get(url);
打印(url);
如果(response.statusCode==200){
data=Herbslist.fromJson(json.decode(response.body));
pages.addAll(data.query.pages.values);
返回数据;
}否则{
投掷(e){
打印(“抛出异常:$e”);
例外情况(e);
};
}
}
}

您可以通过使用
堆栈
小部件并将
循环压缩器指示器
列表视图
重叠来完成此操作。查看下面的代码以获取简化示例:

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;
      });
    });
  }
}
class LoadingOnScroll60619794扩展StatefulWidget{
@凌驾
_LoadingOnScroll60619794State createState()=>_LoadingOnScroll60619794State();
}
类_LoadingOnScroll60619794State扩展状态{
bool\u加载=假;
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
行动:[
图标按钮(
图标:图标(Icons.refresh),
onPressed:运行加载
),
],
),
主体:堆栈(
儿童:[
列表视图(
儿童:[
填充物(
填充:常数边集全部(8.0),
子项:文本(“项目1”),
),
填充物(
填充:常数边集全部(8.0),
子项:文本(“项目1”),
),
填充物(
填充:常数边集全部(8.0),
子项:文本(“项目1”),
),
填充物(
填充:常数边集全部(8.0),
子项:文本(“项目1”),
),
填充物(
填充:常数边集全部(8.0),
子项:文本(“项目1”),
),
填充物(
填充:常数边集全部(8.0),
子项:文本(“项目1”),
),
],
),
_装载
?中心(
子对象:CircularProgressIndicator(),
)
:SizedBox(宽度:0,
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);
    };
  }
}
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,
                                 ),
                            ));
                          }
)
}
}