Flutter 中能夠經過 RefreshIndicator 和 FutrueBuilder 實現異步網絡請求,對於下拉刷新和上滑加載數據也能夠很方便的實現。這裏以知乎日報 API 爲例演示,僅供學習交流。git
在 Flutter 中,異步 UI 更新能夠經過 FutureBuilder 和 StreamBuilder 這兩個組件來實現,對於網絡請求,一般使用 Futrue + FutureBuilder 組合來完成。而對於下拉刷新功能,Flutter 也單獨提供了一個 Widget —— RefreshIndicator 來實現,這個組件有一個 onRefresh 方法,這裏回調異步請求數據的操做就能實現下拉刷新的功能。github
const RefreshIndicator({
Key key,
@required this.child,
this.displacement = 40.0,
@required this.onRefresh,
this.color,
this.backgroundColor,
this.notificationPredicate = defaultScrollNotificationPredicate,
this.semanticsLabel,
this.semanticsValue,
}) : assert(child != null),
assert(onRefresh != null),
assert(notificationPredicate != null),
super(key: key);
複製代碼
對於上滑加載數據,一般經過 ListView 或者其餘可滾動組件的 ScrollController 來完成,經過 ScrollController 能夠判斷滾動列表是否滾動到底部,若是是,就調用上滑加載的功能獲取數據便可。編程
效果:api
這裏以知乎日報 API 爲例說明,兩個 api 以下bash
///最新消息
const String LAST_NEWS = "https://news-at.zhihu.com/api/4/news/latest";
///歷史消息
const String HISTORY_NEWS = "https://news-at.zhihu.com/api/4/news/before/";
複製代碼
使用 Dio 進行網絡請求:微信
Response response = await dio.get(LAST_NEWS);
複製代碼
這裏返回的數據是 Map 類型的,能夠根據 key 直接拿到咱們想要的結果便可。 如,獲取消息中的日期字段:網絡
currentDate = response.data["date"].toString();
複製代碼
FutureBuilder 須要結合 Future 使用,先定義一個 Future,異步網絡請求。異步
///先定義一個 Future
Future getDataFuture;
...
@override
void initState() {
super.initState();
getDataFuture = getItemNews();
}
///獲取最新消息
Future<List<dynamic> > getItemNews() async{
items.clear();
print("開始獲取最新消息.");
response = await dio.get(LAST_NEWS);
currentDate = response.data["date"].toString();
if(response.data["stories"] != null){
items.addAll(response.data["stories"]);
}
return items;
}
複製代碼
FutureBuilder + ListView 展現數據async
FutureBuilder<List<dynamic>>(
///指定刷新數據的 Future
future: getDataFuture,
builder: (context,AsyncSnapshot<List<dynamic>> async){
///正在請求時的視圖
if (async.connectionState == ConnectionState.active || async.connectionState == ConnectionState.waiting) {
return Center(
child: Text("loading..."),
);
}
///發生錯誤時的視圖
if (async.connectionState == ConnectionState.done) {
if (async.hasError) {
return Center(
child: Text("error"),
);
} else if (async.hasData && async.data != null && async.data.length > 0) {
List resultList = async.data;
return ListView.builder(
controller: _scrollController,
itemCount: resultList.length + 1,
itemExtent: 100.0,
itemBuilder: (BuildContext context, int index) {
return index < async.data.length ? Container(
child: Card(
child: Row(
children: <Widget>[
Expanded(
child: Container(
child: Text(resultList[index]["title"].toString(),style: TextStyle(fontSize:20),),
padding: EdgeInsets.symmetric(horizontal: 10),
),
flex: 2,
),
Expanded(
child: Container(
child:Image.network(resultList[index]["images"][0].toString()),
padding: EdgeInsets.all(5),
),
flex: 1,
),
],
),
),
height: 50,
): Center(
child: isShowProgress? CircularProgressIndicator(
strokeWidth: 2.0,
):Container(),
);
}
);
}else{
return Center(
child: Text("error"),
);
}
}
return Center(
child: Text("error"),
);
},
),
複製代碼
上面的代碼已經實現了異步加載和顯示數據的功能,對於下拉刷新,只要在 FutureBuilder 外面嵌套 RefreshIndicator 並指定 onRefresh 便可。ide
RefreshIndicator(
onRefresh: getItemNews,
child: FutureBuilder<List<dynamic>>(
future: getDataFuture,
...
)
)
複製代碼
上滑加載數據經過 ScrollController 來實現:
ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
getDataFuture = getItemNews();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
print("get more");
_getMore(currentDate);
}
});
}
_getMore(String date) async{
if(date == "")
return;
setState(() {
isShowProgress = true;
});
Map<String, dynamic> historyMap ;
response = await dio.get(HISTORY_NEWS + date);
historyMap = response.data;
if(historyMap != null && historyMap.length > 0){
List<dynamic> stories = historyMap["stories"];
if(stories != null && stories.length > 0){
currentDate = historyMap["date"].toString();
}
if(response.data["stories"] != null){
items.addAll(response.data["stories"]);
}
}
setState(() {
isShowProgress = false;
});
}
複製代碼
在 LisbView 裏面,我指定了數據的長度爲返回的數據長度 + 1,目的就是爲了如今最下面的 CircularProgressIndicator 對話框,而上面的變量 isShowProgress 可控制是否顯示這個組件的。
歡迎關注「Flutter 編程開發」微信公衆號 。