很簡單,直接使用
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;
});
}
}
複製代碼