最近项目上的需求需要实现下拉刷新和上拉加载更多的功能,RecyclerView下拉刷新我相信安卓的同学都会做,无非是利用SwipeRefreshLayout,然后给swipeRefreshLayout设置刷新监听,非常简单,所以这里不作赘述。
上拉加载更多,除了必要的逻辑,还需要自己控制loadingView的显示与隐藏,ListView中有一个方法addFooterView()可以轻松实现,在需要显示loadingView的时候设置view的可见性即可。
而RecyclerView中没有相应的方法,因此还需要自己实现。这也是有别于下拉刷新的一个难点。
接下来就一步步实现一个下拉刷新,上拉加载更多的RecyclerView,先来看看最终的效果:
步入正题,先贴出activity的布局代码
只需要达到演示效果就行,布局文件不用太复杂
是个RecyclerView就需要RecyclerView.Adapter,所以接下来我们创建个Adapter类
public class MRecyclerViewAdapter extends RecyclerView.Adapter<MRecyclerViewAdapter.MViewHolder> {
}
其中MViewHolder是个MRecyclerViewAdapter的内部类
class MViewHolder extends RecyclerView.ViewHolder {
View mItemView;
public MViewHolder(@NonNull View itemView) {
super(itemView);
this.mItemView = itemView;
}
}
接下来实现Adpater的三个方法:
其中:
public static final int TYPE_FOOTER = -1001;
public static final int TYPE_NORMAL = -1000;
private List<RecyclerItem> mDataList = new ArrayList<>();
而RecyclerItem是我们自定义的一个实体类,看看它的内部结构
public class RecyclerItem {
public int type; // 布局类型
public String name;
}
RecyclerItem里面除了有必要的字段之外,还有一个type属性,这个属性就是区分不同布局用的。
看到**onCreateViewHolder()**里的实现,判断viewType类型来生成View,如果viewType = TYPE_FOOTER,则生成我们底部的loadingView,也就是正在加载
而onCreateViewHolder()的viewType是由getItemViewType()这个方法返回的,所以我们还要重写这个方法,返回我们RecyclerItem中的type:
@Override
public int getItemViewType(int position) {
return mDataList.get(position).type;
}
我们希望,在RecyclerView滚动底部的时候能够自动创建一个loadingView,但是我们mDataList中如果不添加type = TYPE_FOOTER类型的RecyclerItem,onCreateViewHolder()是不会给我们创建这样一个布局的,所以Adapter中还需要提供一个方法,能够帮我们添加一个type = TYPE_FOOTER的RecyclerItem。
在MRecyclerAdapter中创建方法:
public void addLoadItem() {
if (mDataList.size() > 0
&& mDataList.get(mDataList.size() - 1).type == TYPE_FOOTER)
return;
RecyclerItem footItem = new RecyclerItem();
footItem.type = TYPE_FOOTER;
mDataList.add(footItem);
notifyItemChanged(mDataList.size() - 1);
}
同时,对应的也有removeLoadItem()方法:
public void removeLoadItem() {
if (mDataList.size() == 0)
return;
if (mDataList.get(mDataList.size() - 1).type != TYPE_FOOTER)
return;
mDataList.remove(mDataList.size() - 1);
notifyItemChanged(mDataList.size() - 1);
}
MRecyclerViewAdapter方面的工作准备好了,就剩Activity那边的调用了,给RecyclerView准备Adapter和List数据都是千篇一律的操作,这里不贴他们的代码了,swipeRefreshLayout也是一样。
这里重点关注当RecyclerView滑动到底部时,怎么让loadingView显示出来并进行加载数据的操作。
所以我们要给RecyclerView设置一个滑动的监听,如果当前最后一个ItemView可见了,就显示loadingView。
简单解释一下,当我们最后一个itemView可见了而且此时并没有在刷新,也没有正在加载更多数据的情况下,就调用adapter的addLoadItem()方法,这个方法会帮我们在recyclerview最后面添加一个loadingView的视图并刷新界面。
有朋友反应加载更多时会报 warning,修改onScrolled()方法的部分代码:
if (totalCount > 0) { // 在 recyclerView 滚动时向列表中添加item 并调用 notifyItemInserted() 方法更新时, // 系统会给出 warning: 可能会影响RecyclerView滑动时的高度等测量 // 所以将这次更新 UI 的操作,延迟到下一帧绘制。 recyclerView.post(() -> { mAdapter.addLoadItem(); }) }
接着加载我们的数据调用pullData(),pullData()获取的数据都是本地生成的list,刷新比较快,所以为了更好地演示效果,这里加了1s的延迟。最终的效果,就是文章开头那样啦。
源码地址在这,有需要的朋友自取~
关于RecyclerView的拖拽操作,我还写了另一篇文章来介绍,有兴趣的朋友可以阅读:
高端操作!实现RecyclerView的上下拖拽
兄dei,如果觉得我写的还不错,麻烦帮个忙呗 😃
- 给俺点个赞被,激励激励我,同时也能让这篇文章让更多人看见,(#.#)
- 不用点收藏,诶别点啊,你怎么点了?这多不好意思!
- 噢!还有,我维护了一个路由库。。没别的意思,就是提一下,我维护了一个路由库 =.= !!
拜托拜托,谢谢各位同学!