这个包装类主要有两个关键点:
第一个是列表尾部添加一个条目,用于显示各种加载的状态,就是添加了一个特殊类型的holder。
第二个是监控列表滚动,滚动到我们添加的那个holder的时候,触发我们需要的操作,比如修改holder里的状态文字等。
注意问题:
以前做过两一个实现方案,主要的区别在第二点,方案没有监控列表滚动,而是在添加的尾部的holder绑定操作的时候,进行回调加载更多方案,然后在会掉中更新列表,原来类似。
原理介绍
1.添加一个新的类型的itemview用于显示我们的加载状态
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1) {
return R.layout.lib_base_list_item_loading;
} else {
return mAdapter.getItemViewType(position);
}
}
2.创建holder的时候需要做区分,绑定holder的时候去更新一下我们添加的holder上的文字状态。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == R.layout.lib_base_list_item_loading) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
return new LoadingHolder(view, onLoadOrRetryListener);
} else {
return mAdapter.onCreateViewHolder(parent, viewType);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof LoadingHolder) {
((LoadingHolder) holder).bindHolder(mLoadState);
} else {
mAdapter.onBindViewHolder(holder, position);
}
}
3.设置一个监听器,监听RecyclerView.OnScrollListener的滚动事件,在这里进行调用加载更多的方法回调。
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (nextPageId == 0) {
return;
}
int itemCount = mLayoutManager.getItemCount();
int lastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
//最后显示的view是不是我们列表的最后一个数据
if (lastVisibleItemPosition == itemCount - 1) {
//这个时候的刷新状态
int loadState = mAdapter.getLoadState();
//这里限制哪几种状态不用调用onLoadMore(nextPageId); 方法
if (!isLoading && hasMore==LoadMoreAdapterWrapper.STATE_LOADING && loadState != LoadMoreAdapterWrapper.STATE_LOAD_FAILED
&& loadState != LoadMoreAdapterWrapper.STATE_LOAD) {
isLoading = true;
//通过hanlder调用方法,防止出现异常
new Handler().post(new Runnable() {
@Override
public void run() {
onLoadMore(nextPageId);
}
});
}
}
}
4.更新状态的方法外部调用该方法来,改变最后一个view的状态。下面是我使用到的状态,可以根据自己的需求进行调成。
public void updatePageInfo(int nextPageId, int hasMore) {
this.nextPageId = nextPageId;
this.hasMore = hasMore;
this.isLoading = false;
switch (hasMore) {
case STATE_LOAD:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD);
break;
case STATE_LOADING:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOADING);
break;
case STATE_LOAD_FAILED:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_FAILED);
break;
case STATE_LOAD_HIDE:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_HIDE);
break;
case STATE_LOAD_HAVE_NO_DATA:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_HAVE_NO_DATA);
break;
}
mAdapter.notifyDataSetChanged();
}
以上就是关键的实现点了。
补充一点,就是在布局书网格的布局时,需要对loading布局进行处理,否则显示会不正确,现象为loading布局只能显示在第一个单元格内
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
// 如果当前是footer的位置,那么该item占据2个单元格,正常情况下占据1个单元格
return getItemViewType(position) == TYPE_FOOTER ? gridManager.getSpanCount() : 1;
}
});
}
}
使用步骤一:
你需要让你的adapter继承BaseRecyclerViewAdapter,主要是为了使用里面的一些操作列表的方法。
使用步骤二:注释的比较详细
//要包装的adapter
dateBaseAdapter = new DateBaseAdapter(this);
dateBaseAdapter.appendData(objects);
//布局管理器
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//adapter包装类初始化,将自己的adapter 穿入
LoadMoreAdapterWrapper stringWrapperAdapter = new LoadMoreAdapterWrapper<>(this, dateBaseAdapter);
//初始化我们自己的监听方法
onLoadMoreListener = new LoadMoreAdapterWrapper.OnLoadMoreListener(linearLayoutManager, stringWrapperAdapter) {
@Override
public void onLoadMore(int nextPageId) {
LogUtils.d("--------" + page);
viewById.postDelayed(new Runnable() {
@Override
public void run() {
page++;
onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOAD_FAILED);
dateBaseAdapter.appendData(objects);
}
}, 1000);
}
};
stringWrapperAdapter.setOnLoadOrRetryListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewById.postDelayed(new Runnable() {
@Override
public void run() {
page++;
onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOAD);
dateBaseAdapter.appendData(objects);
}
}, 1000);
}
});
//第一次更新状态
onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOADING);
//将监听方法设置给recycler view
viewById.addOnScrollListener(onLoadMoreListener);
viewById.setLayoutManager(linearLayoutManager);
viewById.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.HORIZONTAL));
//将包装类设置给recycler view
viewById.setAdapter(stringWrapperAdapter);
总结一下
虽然很多大神写过这类文章,但是只有自己动手实践过才能更好的理解。