很简单,直接使用
RefreshIndicator
组件,onRefresh
为从新获取数据的方法服务器
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.all(2.0),
child: RefreshIndicator(
onRefresh: _refresh,
backgroundColor: Colors.blue,
child: ListView.builder(
itemCount: _dataList.length,
itemBuilder: (context, index) {
return ListItem(_dataList[index]);
},
),
),
),
);
}
Future<Null> _refresh() async {
_dataList.clear();
await _loadFirstListData();
return;
}
复制代码
咱们先看一下效果app
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<int> items = List.generate(10, (i) => i);
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Infinite ListView"),
),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(title: new Text("Number $index"));
},
),
);
}
}
复制代码
http
请求Future<List<int>> fakeRequest(int from, int to) async {
return Future.delayed(Duration(seconds: 2), () {
return List.generate(to - from, (i) => i + from);
});
}
复制代码
ListView
滑动到最末端的触发 fakeRequest
来加载更多数据,最简单的实现方式就是使用 ScrollController
来完成,ScrollController
会监听滚动事件,当 ListView
滚动到末端的时候他会发出一个请求。在这里还有一件须要注意的事就是为了不对服务器不断地请求,咱们须要作一个标记 isPerformingRequest
只有当它为 false
的时候才容许对后台进行请求。class _MyHomePageState extends State<MyHomePage> {
List<int> items = List.generate(10, (i) => i);
ScrollController _scrollController = new ScrollController();
bool isPerformingRequest = false;
@override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
_getMoreData();
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
_getMoreData() async {
if (!isPerformingRequest) {
setState(() => isPerformingRequest = true);
List<int> newEntries = await fakeRequest(items.length, items.length + 10);
setState(() {
items.addAll(newEntries);
isPerformingRequest = false;
});
}
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Infinite ListView"),
),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(title: new Text("Number $index"));
},
controller: _scrollController,
),
);
}
}
复制代码
若是你如今运行程序你将会看到咱们的列表已经能够实现动态加载了,可是这距离咱们的目标还很远,咱们须要添加一些标志动做让用户这道请求已经开始。async
CircularProgressIndicator
去完成这个加载标志Widget _buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isPerformingRequest ? 1.0 : 0.0,
child: new CircularProgressIndicator(),
),
),
);
}
复制代码
ListView
中去,注意这里要给 itemCount
加出一块空间来放置咱们的 _buildProgressIndicator
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Infinite ListView"),
),
body: ListView.builder(
itemCount: items.length + 1,
itemBuilder: (context, index) {
if (index == items.length) {
return _buildProgressIndicator();
} else {
return ListTile(title: new Text("Number $index"));
}
},
controller: _scrollController,
),
);
}
复制代码
ListView
向下移动覆盖正在加载更多数据的标志_getMoreData() async {
if (!isPerformingRequest) {
setState(() => isPerformingRequest = true);
List<int> newEntries = await fakeRequest(items.length, items.length); //returns empty list
if (newEntries.isEmpty) {
double edge = 50.0;
double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels;
if (offsetFromBottom < edge) {
_scrollController.animateTo(
_scrollController.offset - (edge -offsetFromBottom),
duration: new Duration(milliseconds: 500),
curve: Curves.easeOut);
}
}
setState(() {
items.addAll(newEntries);
isPerformingRequest = false;
});
}
}
复制代码