学习目标
熟悉和掌握 XRecyclerView 的上拉加载更多功能的实现过程
这是接着上一篇文章 阅读XRecyclerView源码一,对 XRecyclerView 的下拉加载更多功能的说明。
源码分析
LoadingMoreFooter
在自定义的上拉加载更多的控件 LoadingMoreFooter
中,setState(int state)
方法主要是针对上拉加载的各种状态对该控件进行相关操作。
// 设置加载过程状态,及控件的显示与隐藏
public void setState(int state) {
switch (state) {
case STATE_LOADING:
simpleViewSwitcher.setVisibility(VISIBLE);
mText.setText(loadingHint);
this.setVisibility(VISIBLE);
break;
case STATE_COMPLETE:
mText.setText(loadingDownHint);
this.setVisibility(GONE);
break;
case STATE_NOMORE:
mText.setText(noMoreHint);
simpleViewSwitcher.setVisibility(GONE);
this.setVisibility(VISIBLE);
break;
}
}
XRecyclerView
类中的 isLoadingData
参数主要是为了控制在下拉刷新的时候禁止上拉加载,在上拉加载的时候禁止下拉刷新。
关于上拉加载功能的实现,主要是重写 onScrollStateChanged(int state)
方法,在 RecyclerView.SCROLL_STATE_IDLE
状态,获得当前的 lastVisibleItemPosition
这个参数的值,再进行操作。
// 处理加载更多, 主要是 lastVisibleItemPosition
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
// SCROLL_STATE_IDLE 状态 滑动停止
if (state == RecyclerView.SCROLL_STATE_IDLE && mLoadingListener != null && !isLoadingdata) {
// 获得并判断 LayoutManager,得到最终的 lastVisibleItemPosition
LayoutManager layoutManager = getLayoutManager();
int lastVisibleItemPosition;
if (layoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
// 瀑布流布局发现最后的可见 item 位置
int [] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into);
lastVisibleItemPosition = findMax(into);
} else {
lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
}
// 加载更多的子 view 存在 && 最后可见的 item 位置 >= adapter 的 items 数量 - 1----当上拉显示到最后一个 item 的时候
// itemCount 的数量 > XRecyclerView 中子 view 的数量(2 + getHeaderViews()) && 还有更多加载 && 下拉刷新头状态没有处在正刷新
if (layoutManager.getChildCount() > 0 && lastVisibleItemPosition >= layoutManager.getItemCount() - 1
&& layoutManager.getItemCount() > layoutManager.getChildCount() && !isNoMore &&
mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
isLoadingdata = true;
if (mFootView instanceof LoadingMoreFooter) {
((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_LOADING);
} else {
mFootView.setVisibility(VISIBLE);
}
mLoadingListener.onLoadMore();
}
}
}
需要注意的是在 RecyclerView 的 LayoutManager
为 StaggeredGridLayoutManager
时,获取 lastVisibleItemPosition
值的方法稍有变化。在获得到 lastVisibleItemPosition 的值后,对它的判断条件稍微多了点,主要就是判断它是不是最后一条 item 数据位置,然后就是对 LoadingMoreFooter
状态设置为 STATE_LOADING
,再调用接口的 onLoadMore()
方法,进行具体操作。
loadMoreComplete() 方法
public void loadMoreComplete() {
isLoadingData =false; // 将加载状态置为 false
if (mFootView instanceof LoadingMoreFooter) { // 如果是该自定义 LoadingMoreFooter,直接设置状态即可
((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_COMPLETE);
} else { // 自己重新定义的 view 则设置隐藏
mFootView.setVisibility(GONE);
}
}
在数据加载完成后,调用这个方法结束加载状态。
setNoMore() 方法
// 设置是否还有更多下拉加载
public void setNoMore(boolean noMore) {
isLoadingData = false; // 将加载状态置为 false
isNoMore = noMore;
if (mFootView instanceof LoadingMoreFooter) {
// 根据 noMore 值来设置 LoadingMoreFooter 状态是 NOMORE 还是 COPMPLTETE
((LoadingMoreFooter) mFootView).setState(isNoMore ?
LoadingMoreFooter.STATE_NOMORE:LoadingMoreFooter.STATE_COMPLETE);
} else {
mFootView.setVisibility(GONE);
}
}
全部数据加载完成,调用这个方法,改变 LoadingMoreFooter
的加载状态及 UI
显示。
WrapAdapter
在 WrapAdapter
中,主要是在 getItemViewType()
和 getItemCount()
方法添加了 footView
的返回类型,和增加的 itemCount
。
@Override
public int getItemCount() {
if (loadingMoreEnable) {
if (adapter != null) {
return getHeadersCount() + adapter.getItemCount() + 2;
} else {
return getHeadersCount() + 2;
}
} else {
if (adapter != null) {
return getHeadersCount() + adapter.getItemCount() + 1;
} else {
return getHeadersCount() + 1;
}
}
}
// 设置 ViewType
@Override
public int getItemViewType(int position) {
int adjPosition = position - (getHeadersCount() + 1);
if (isRefreshHeader(position)) {
return TYPE_REFRESH_HEADER;
}
if (isHeader(position)) {
position = position - 1;
return mHeaderTypes.get(position);
}
if (isFooter(position)) {
return TYPE_FOOTER;
}
int adapterCount;
if (adapter != null) {
adapterCount = adapter.getItemCount();
if (adjPosition < adapterCount) {
int type = adapter.getItemViewType(adjPosition);
if (isReservedItemViewType(type)) {
throw new IllegalStateException("XRecyclerView require itemViewType in adapter should be less than 10000 " );
}
return type;
}
}
return 0;
}
总结
XRecyclerView 的上拉加载功能的实现,通过自定义的 LoadingMoreFooter
类,在该类中添加进了 AVLoadingIndicatorView
控件作为加载时动画效果,暴露 setState(int state)
方法,对上拉加载的不同状态进行对应设置。在 XRecyclerView 类中主要重写 onScrollStateChanged(int state)
方法,得到 lastVisibleItemposition
的值,进行加载动作 mLoadingListener.onLoadMore()
,加载完成后调用 loadMoreComplete()
方法,全部数据完成再调用 setNoMore(treu)
方法。