3分钟
06 上下刷新列表
毫无争议,必备控件。
Flutter 中 为我们提供了 RefreshIndicator
作为内置下拉刷新控件;同时我们通过给 ListView
添加 ScrollController
做滑动监听,在最后增加一个 Item, 作为上滑加载更多的 Loading 显示。
如下代码所示,通过 RefreshIndicator
控件可以简单完成下拉刷新工作,这里需要注意一点是:可以利用 GlobalKey
对外提供 RefreshIndicator
的 RefreshIndicatorState
,这样外部就 可以通过 GlobalKey 调用 globalKey.currentState.show();
,主动显示刷新状态并触发 onRefresh
。
上拉加载更多在代码中是通过 _getListCount()
方法,在原本的数据基础上,增加实际需要渲染的 item 数量给 ListView 实现的,最后通过 ScrollController
监听到底部,触发 onLoadMore
。
如下代码所示,通过 _getListCount()
方法,还可以配置空页面,头部等常用效果。其实就是在内部通过改变实际item数量与渲染Item,以实现更多配置效果。
class _GSYPullLoadWidgetState extends State<GSYPullLoadWidget> {
///···
final ScrollController _scrollController = new ScrollController();
@override
void initState() {
///增加滑动监听
_scrollController.addListener(() {
///判断当前滑动位置是不是到达底部,触发加载更多回调
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
if (this.onLoadMore != null && this.control.needLoadMore) {
this.onLoadMore();
}
}
});
super.initState();
}
///根据配置状态返回实际列表数量
///实际上这里可以根据你的需要做更多的处理
///比如多个头部,是否需要空页面,是否需要显示加载更多。
_getListCount() {
///是否需要头部
if (control.needHeader) {
///如果需要头部,用Item 0 的 Widget 作为ListView的头部
///列表数量大于0时,因为头部和底部加载更多选项,需要对列表数据总数+2
return (control.dataList.length > 0) ? control.dataList.length + 2 : control.dataList.length + 1;
} else {
///如果不需要头部,在没有数据时,固定返回数量1用于空页面呈现
if (control.dataList.length == 0) {
return 1;
}
///如果有数据,因为部加载更多选项,需要对列表数据总数+1
return (control.dataList.length > 0) ? control.dataList.length + 1 : control.dataList.length;
}
}
///根据配置状态返回实际列表渲染Item
_getItem(int index) {
if (!control.needHeader && index == control.dataList.length && control.dataList.length != 0) {
///如果不需要头部,并且数据不为0,当index等于数据长度时,渲染加载更多Item(因为index是从0开始)
return _buildProgressIndicator();
} else if (control.needHeader && index == _getListCount() - 1 && control.dataList.length != 0) {
///如果需要头部,并且数据不为0,当index等于实际渲染长度 - 1时,渲染加载更多Item(因为index是从0开始)
return _buildProgressIndicator();
} else if (!control.needHeader && control.dataList.length == 0) {
///如果不需要头部,并且数据为0,渲染空页面
return _buildEmpty();
} else {
///回调外部正常渲染Item,如果这里有需要,可以直接返回相对位置的index
return itemBuilder(context, index);
}
}
@override
Widget build(BuildContext context) {
return new RefreshIndicator(
///GlobalKey,用户外部获取RefreshIndicator的State,做显示刷新
key: refreshKey,
///下拉刷新触发,返回的是一个Future
onRefresh: onRefresh,
child: new ListView.builder(
///保持ListView任何情况都能滚动,解决在RefreshIndicator的兼容问题。
physics: const AlwaysScrollableScrollPhysics(),
///根据状态返回子孔健
itemBuilder: (context, index) {
return _getItem(index);
},
///根据状态返回数量
itemCount: _getListCount(),
///滑动监听
controller: _scrollController,
),
);
}
///空页面
Widget _buildEmpty() {
///···
}
///上拉加载更多
Widget _buildProgressIndicator() {
///···
}
}
学员评价