Future<void> _onRefresh() async {
await Future.delayed(Duration(seconds: 2)).then((e){
setState(() {
_items.clear();
for (int i=0;i<20;i++){
_items.insert(_items.length, "第${_items.length}条下拉刷新后的数据");
}
});
});
}
先缕一下实现的思路,我们想要实现的效果是每页20条内容,共5页的内容,1-4页末尾数据后要展示加载新数据的loading,到第5页末尾数据展示“我是有底线的”,因此,我们的itemCount就要是itemCount: _items.length + 1.而不是itemCount: _items.length + 1,这是因为要在最后留出来loading的位置,接下来就是要处理构建LisvtView里面的每一条item,如果当前item的索引是列表数据的最后一条数据,并且不是最后一页的话,展示loading,如果当前item的索引是列表数据的最后一条数据,并且是最后一页的话,展示“我是有底线的”,如果当前item的索引不是列表数据的最后一条,则展示下一条数据的内容。最后要处理的就是当页面滑动到最后了,要怎么获取新的数据。前面我们在写页面滑动的部分有讲到过controller属性(此属性接收一个ScrollController对象,ScrollController的主要作用是控制滚动位置和监听滚动事件),我们现在需要做的就是通过ListView的controller控制器来判断页面是否滑动到了最底部,如果滑动到了最底部,则获取新的数据并插入到list里面,最后通过setState通知页面重新构建。
import 'package:flutter/material.dart';
void main() => runApp(DemoApp());
class DemoApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _DemoAppState();
}
}
class _DemoAppState extends State<DemoApp> {
ScrollController _controller = new ScrollController();
var _items = new List<String>();
var _mPage = 0;
@override
void initState() {
super.initState();
getData();
//给_controller添加监听
_controller.addListener((){
//判断是否滑动到了页面的最底部
if(_controller.position.pixels == _controller.position.maxScrollExtent){
//如果不是最后一页数据,则生成新的数据添加到list里面
if(_mPage < 4){
_retrieveData();
}
}
});
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'ListView Demo',
home: new Scaffold(
appBar: new AppBar(
title: new Text('ListView Demo'),
),
body: new RefreshIndicator(
onRefresh: _onRefresh,
child: new ListView.separated(
controller: _controller,
physics: BouncingScrollPhysics(),
itemBuilder: (context,index){
//判断是否构建到了最后一条item
if(index == _items.length){
//判断是不是最后一页
if(_mPage < 4){
//不是最后一页,返回一个loading窗
return new Container(
padding: EdgeInsets.all(16.0),
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
child: CircularProgressIndicator(strokeWidth: 2.0,),
),
);
}else{
//是最后一页,显示我是有底线的
return new Container(
padding: EdgeInsets.all(16.0),
alignment: Alignment.center,
child: new Text('我是有底线的!!!',style:TextStyle(color: Colors.blue),),
);
}
}else{
return ListTile(title:new Text('${_items[index]}'));
}
},
//分割线构造器
separatorBuilder: (context,index){
return new Divider(color: Colors.blue,);
},
//_items.length + 1是为了给最后一行的加载loading留出位置
itemCount: _items.length + 1
),
),
),
);
}
void getData() {
//初始数据源
for (int i=0;i<20;i++){
_items.insert(_items.length, "第${_items.length}条原始数据");
print(_items[i]);
}
}
void _retrieveData() {
//上拉加载新的数据
_mPage++;
Future.delayed(Duration(seconds: 2)).then((e){
for (int i=0;i<20;i++){
_items.insert(_items.length, "这是新加载的第${_items.length}条数据");
}
setState(() {
});
});
}
Future<void> _onRefresh() async {
await Future.delayed(Duration(seconds: 2)).then((e){
setState(() {
_mPage = 0;
_items.clear(