下拉刷新
很簡單,直接使用
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;}
復制代碼
上拉加載更多
我們先看一下效果
- 讓我們先從最原始的十條的數據開始
class MyHomePage extends StatefulWidget {@override_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {List<int> items = List.generate(10, (i) => i);@overridevoid initState() {super.initState();}@overridevoid dispose() {super.dispose();}@overrideWidget 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;@overridevoid initState() {super.initState();_scrollController.addListener(() {if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {_getMoreData();}});}@overridevoid 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;});}}@overrideWidget 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,),);}
}
復制代碼
如果你現在運行程序你將會看到我們的列表已經可以實現動態加載了,但是這距離我們的目標還很遠,我們需要添加一些標志動作讓用戶這道請求已經開始。
- 接下來我們要用到
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 listif (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;});}
}
復制代碼