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 编程开发」微信公众号 。