- 概述
RecyclerView是一个比ListView更加灵活的View,它通过设置LayoutManager来布局子item,常见的LayoutManager有LinearLayoutManager、GridLayoutManager和StaggeredGridLayoutManager(交错布局)。那么我们应该怎样来实现通用的RecyclerView上拉加载与下拉刷新呢?
- 实现思路
在看实现思路之前先看看最终的效果图:第一次制作gif图哈,效果有点问题,里面的所有图片都来自gank.io,还有我自己的练习项目Gank.IO正在开发中欢迎start和给我提一些建议。这个是我的git地址:https://github.com/xiaolutang/GankIo.git。项目现在十分的low希望以后有机会让它变得更加好吧。
扯了那么多的蛋终于要说到实现思路了,首先我们通过重写RecyclerView的Adapter类未recyclerView添加头部和尾部。如何添加Apdater的思想我就不自己写了,这里我参考学习了鸿洋大神的一片文章有兴趣可以自己看看Android 优雅的为RecyclerView添加HeaderView和FooterView地址是https://blog.csdn.net/lmj623565791/article/details/51854533。在下拉的时候通过设置顶部view的marginTop来实现下拉效果。同理尾部通过改变尾部view的marginBottom来实现效果。
- 整体结构设计类图
IRefreshListener:这几接口定义了RecyclerView加载更多和刷新方法。当下拉刷新和上拉加载的时候回自动调用,
IPullRefresh:这个接口定义了v头部和尾部添加的view的状态更改和变化。
AbsPullRefreshView:是一个抽象类,实现了IPullRefresh接口
CommonPullRefreshView: 通用的头部和尾部
PullRefreshRecyclerView:能够实现上拉加载和下拉刷新的RecyclerView
- 基本实现
PullRefreshRecyclerView:复写setAdapter方法,在AdapterWrapter中保存实际的adapter,RecyclerView的adapter实际上是AdapterWrapter对象
public class PullRefreshRecyclerView extends RecyclerView {
private final String TAG = PullRefreshRecyclerView.class.getSimpleName();
/**
* 阻尼效果
*/
private final float OFFSET_RADIO = 1.5f;
/**
* 是否可以下拉 默认可以
*/
private boolean mEnablePullRefresh = true;
private Context context;
private AbsPullRefreshView mHeader;
private AbsPullRefreshView mFooter;
private AdapterWrapper adapterWrapper;
private OnPullRefreshListener listener;
public PullRefreshRecyclerView(Context context) {
this( context,null );
}
public PullRefreshRecyclerView(Context context, @Nullable AttributeSet attrs) {
this( context, attrs, 0);
}
public PullRefreshRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super( context, attrs, defStyle );
this.context = context;
}
private void init(){
mHeader = new CommonPullRefreshView(context,this,AbsPullRefreshView.VIEW_TYPE_HEADER);
mHeader.updateViewState( AbsPullRefreshView.VIEW_STATE_RUNNING );
mFooter = new CommonPullRefreshView( context,this,AbsPullRefreshView.VIEW_TYPE_FOOTER );
adapterWrapper.AddHeaderView( mHeader.getView( context,this ) );
adapterWrapper.addFootView( mFooter.getView( context,this ) );
}
@Override
public void setAdapter(Adapter adapter) {
adapterWrapper = new AdapterWrapper( adapter );
adapter.registerAdapterDataObserver( new AdapterDataObserver() {
@Override
public void onChanged() {
adapterWrapper.notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
adapterWrapper.notifyItemRangeChanged( positionStart+adapterWrapper.mHeaderViews.size(),itemCount );
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
adapterWrapper.notifyItemRangeChanged( positionStart+adapterWrapper.mHeaderViews.size(),itemCount );
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
adapterWrapper.notifyItemRangeInserted( positionStart+adapterWrapper.mHeaderViews.size(),itemCount );
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
adapterWrapper.notifyItemRangeRemoved( positionStart+adapterWrapper.mHeaderViews.size(),itemCount );
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
adapterWrapper.notifyDataSetChanged();
}
} );
init();
super.setAdapter( adapterWrapper );
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent( ev );
}