很多APP中都需要列表支持上拉刷新下拉加载更多的操作,网上也有很多例子,实现方法不在说明,论坛中太多了,由于没有找到自己合适的demo,自己参照各个大神的代码进行了修改,由于参考了比较多的别人的博客,自己也记不清楚了,不再贴出参考博客地址了,非常抱歉。
主要实现功能:
1.上拉加载更多,并可以代码控制是否需要
2.下拉加载更多,通过初始化参数进行配置是否需要
3.当数据不足以展示当前recyclerview的高度时,不显示“上拉加载更多”(主要是这个进行了自定义)
4.当数据没有更多时不再加载更多,并显示“没有更多数据”(这个在别人demo中也没找到)
使用也比较简单:
1、由于自定义pullrecyclerview类继承自linearlayout,使用时在布局文件中可直接定义pullrecyclerview标签
2、在使用的activity或fragment中的oncreat中进行初始化 pullrecyclerview.init(),传入三个参数,a,滑动列表的接口类ipullrecyclerview类,并实现两个方法b,布局管理器layoutmanager(只支持linearlayoutmanager和gridlayoutmanager),c,列表的adapter(原生的直接按正常的写就可以)
3、在activity或fragment中进行网络请求或其他方式获取数据,自己写的adapter进行数据加载(一般是构造方法中传入list),之后必须调用pullrecyclerview.LoadCompleted();
贴出代码:
自定义的pullrecyclerview类
public class PullRecyclerView extends LinearLayout implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "PullRecyclerView";
private static final int LOADTYPE_NOMORE = -1;
private static final int LOADTYPE_LOADING = 0;
private static final int LOADTYPE_HADMORE = 1;
private Context mContext;
private SwipeRefreshLayout vSwfLayout;
private RecyclerView vRecyclerView;
private IPullRecyclerView mIPullRecyclerView;
/*自己的adapter原生的继承自recyclerview.adapter的*/
private RecyclerView.Adapter mAdapter;
/*本类中用到的adapter*/
private AdapterWrapper mAdapterWrapper;
/*加载更多的holder,可以通过修改此Holder进行自定义样式*/
private AdapterWrapper.WrapperHolder mWrapperHolder;
private RecyclerView.LayoutManager mLayoutManager;
/*线性布局*/
public static final int ADAPTER_TYPE_LINEAR = 0x01;
/*网格布局*/
public static final int ADAPTER_TYPE_GRID = 0x02;
/*默认为线性布局*/
private int mAdapterType = ADAPTER_TYPE_LINEAR;
/*view type : "上拉加载更多"*/
private static final int ITEM_TYPE_LOAD = Integer.MAX_VALUE / 2;
/*是否显示加载更多的item*/
private boolean mShowLoadItem = false;
/*当为gridlayoutmanager时列的数量*/
private int mSpanCount;
/*下拉加载是否正在加载中*/
private boolean mLoading = false;
/*下拉加载功能是否开启*/
private boolean mIsSwipeToLoadEnabled = true;
/*当前列表的item数量*/
private int itemCount;
/*是否是加载更多用于加载完成后刷新是是否显示没有更多了*/
private boolean isLoadMore;
/*全部数据已经加载完*/
private boolean noMoreData;
public PullRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
public PullRecyclerView(Context context) {
super(context);
initView(context);
}
public PullRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
}
/*初始化视图*/
private void initView(Context context) {
this.mContext = context;
View view = LayoutInflater.from(context).inflate(R.layout.view_pullrecyclerview, this);
vSwfLayout = view.findViewById(R.id.pullrecyclerview_swflyout);
vRecyclerView = view.findViewById(R.id.pullrecyclerview_recyview);
}
/*recyclerview设置的adapter*/
private class AdapterWrapper extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_TYPE_LOAD) {
if (mWrapperHolder == null) {
mWrapperHolder = new WrapperHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_loadmore, parent, false));
}
return mWrapperHolder;
} else {
return mAdapter.onCreateViewHolder(parent, viewType);
}
}
// 允许显示"加载更多"item, 并且position为末尾时,展示加载更多的item
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (position == itemCount - 1) {
//最后一项是否显示,以及是否加载完成
showLoadMore(mShowLoadItem);
} else if (position < mAdapter.getItemCount()) {
// 正常情况
holder.itemView.setVisibility(View.VISIBLE);
mAdapter.onBindViewHolder(holder, position);
} else {
// 网格的补空的情况
holder.itemView.setVisibility(View.INVISIBLE);
}
}
@Override
public int getItemCount() {
int resultCount = 0;
if (mAdapterType == ADAPTER_TYPE_LINEAR) {
// 线性布局
resultCount = mAdapter.getItemCount() + 1;
} else {
int remain = mAdapter.getItemCount() % mSpanCount; // 余数
if (remain == 0) {
resultCount = mAdapter.getItemCount() + 1;
} else {
// 余数不为0时,先凑满再加1
resultCount = mAdapter.getItemCount() + 1 + (mSpanCount - remain);
}
}
if (isLoadMore) {
if (itemCount == resultCount) {
noMoreData = true;
}
isLoadMore = false;
}
itemCount = resultCount;
return resultCount;
}
private void showLoadMore(boolean show) {
if (show) {
mWrapperHolder.itemView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, FormatUtil.dp2px(mContext, 50f)));
mWrapperHolder.itemView.setVisibility(VISIBLE);
if (noMoreData) {
setLoadItemState(LOADTYPE_NOMORE);
}
} else {
mWrapperHolder.itemView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0));
mWrapperHolder.itemView.setVisibility(GONE);
}
}
@Override
public int getItemViewType(int position) {
int viewtype = 0;
// 当显示"加载更多"条目, 并且位置是最后一个时, wrapper进行拦截
if (position == itemCount - 1) {
viewtype = ITEM_TYPE_LOAD;// 注意要避免和原生adapter返回值重复
} else {
// 其他情况交给原生adapter处理
viewtype = mAdapter.getItemViewType(position);
}
return viewtype;
}
/*设置加载的type */
private void setLoadItemState(int type) {
switch (type) {
case LOADTYPE_HADMORE:
mWrapperHolder.setLoadText("上拉加载更多");
mWrapperHolder.setLoadPbVisibility(false);
break;
case LOADTYPE_LOADING:
mWrapperHolder.setLoadText("正在加载...");
mWrapperHolder.setLoadPbVisibility(true);
break;
case LOADTYPE_NOMORE:
mWrapperHolder.setLoadText("没有更多了");
mWrapperHolder.setLoadPbVisibility(false);
break;
default:
break;
}
}
class WrapperHolder extends RecyclerView.ViewHolder {
TextView mLoadTv;
ProgressBar mLoadPb;
WrapperHolder(View itemView) {
super(itemView);
mLoadTv = itemView.findViewById(R.id.item_load_tv);
mLoadPb = itemView.findViewById(R.id.item_load_pb);
}
void setLoadText(CharSequence text) {
mLoadTv.setText(text);
}
void setLoadPbVisibility(boolean show) {
mLoadPb.setVisibility(show ? View.VISIBLE : View.GONE);
}
}
}
/*设置滑动监听,关键代码,触发下拉刷新的操作*/
private void addOnScrollListener() {
vRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (mIsSwipeToLoadEnabled && mShowLoadItem && SCROLL_STATE_IDLE == newState && !mLoading && !noMoreData) {
if (mLayoutManager instanceof GridLayoutManager) {
final GridLayoutManager gridLayoutManager = (GridLayoutManager) mLayoutManager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (mIsSwipeToLoadEnabled) {
// 功能开启, 根据位置判断, 最后一个item时返回整个宽度, 其他位置返回1
// AdapterWrapper会保证最后一个item会从新的一行开始
if (position == mLayoutManager.getItemCount() - 1) {
return gridLayoutManager.getSpanCount();
} else {
return 1;
}
} else {
return 1;
}
}
});
}
if (mLayoutManager instanceof LinearLayoutManager) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mLayoutManager;
int lastCompletePosition = linearLayoutManager.findLastCompletelyVisibleItemPosition();
// 当最后一个加载更多显示不完整时回弹隐藏加载更多
if (lastCompletePosition == mLayoutManager.getItemCount() - 2) {
int firstCompletePosition = linearLayoutManager.findFirstCompletelyVisibleItemPosition();
View child = linearLayoutManager.findViewByPosition(lastCompletePosition);
if (child == null)
return;
int deltaY = recyclerView.getBottom() - recyclerView.getPaddingBottom() - child.getBottom();
if (deltaY > 0 && firstCompletePosition != 0) {
recyclerView.smoothScrollBy(0, -deltaY);
}
} else if (lastCompletePosition == mLayoutManager.getItemCount() - 1) {
// 最后一项完全显示, 触发操作, 执行加载更多操作 禁用回弹判断
mLoading = true;
mAdapterWrapper.setLoadItemState(LOADTYPE_LOADING);
mIPullRecyclerView.onLoadMore();
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
/*dy>0时说明向上滑动了,也就是列表当前页面展示不完数据,则展示加载更多的item*/
if (dy > 0) {
if (!mShowLoadItem) {
mShowLoadItem = true;
mAdapterWrapper.notifyItemChanged(itemCount - 1);
}
}
}
});
}
/*设置layoutmanager*/
private void setLayoutManager(RecyclerView.LayoutManager manager) {
this.mLayoutManager = manager;
vRecyclerView.setLayoutManager(mLayoutManager);
if (mLayoutManager instanceof GridLayoutManager) {
mAdapterType = ADAPTER_TYPE_GRID;
mSpanCount = ((GridLayoutManager) mLayoutManager).getSpanCount();
} else if (mLayoutManager instanceof LinearLayoutManager) {
mAdapterType = ADAPTER_TYPE_LINEAR;
}
}
/*刷新要执行的操作,由重写接口决定*/
@Override
public void onRefresh() {
if (mIPullRecyclerView != null) {
mIPullRecyclerView.onRefresh();
mShowLoadItem = false;
noMoreData = false;
}
}
/*===================================我是分割线================================================================================================*/
/*===================================我是分割线================================================================================================*/
/*===================================我是分割线================================================================================================*/
/**
* @param mIPullRecyclerView 需要实现的接口类,fragment或者activity继承此类实现方法即可
* @param mLayoutManager 设置layoutmanager
* @param mAdapter 自己的adapter,原生的
* @describe 初始化滑动列表
*/
public void init(IPullRecyclerView mIPullRecyclerView, RecyclerView.LayoutManager mLayoutManager, @NonNull RecyclerView.Adapter mAdapter) {
this.mIPullRecyclerView = mIPullRecyclerView;
this.mAdapter = mAdapter;
setLayoutManager(mLayoutManager);//设置布局管理器
mAdapterWrapper = new AdapterWrapper();
vRecyclerView.setAdapter(mAdapterWrapper);
//如果是线性布局,添加自定义的分割线,把最后一条分割线去掉,否则在隐藏加载更多时最后面的分割线会两条重叠
if (mLayoutManager instanceof LinearLayoutManager) {
vRecyclerView.addItemDecoration(new WipeEndDecoration(mContext, RecyclerView.VERTICAL, R.drawable.wipeenddivider, 0));
}
if (mIPullRecyclerView == null) {
mIsSwipeToLoadEnabled = false;
vSwfLayout.setEnabled(false);
} else {
mIsSwipeToLoadEnabled = true;
vSwfLayout.setOnRefreshListener(this);
addOnScrollListener();
}
}
/*设置是否可以刷新*/
public void setRefreshEnabled(boolean enabled) {
vSwfLayout.setEnabled(enabled);
if (enabled) {
vSwfLayout.setOnRefreshListener(this);
}
}
/*加载和刷新完成后必须调用此方法*/
public void LoadCompleted() {
if (mLoading) {
mLoading = false;
isLoadMore = true;
} else {
vSwfLayout.setRefreshing(false);
}
mAdapterWrapper.setLoadItemState(LOADTYPE_HADMORE);
mAdapterWrapper.notifyDataSetChanged();
}
/*得到recyclerview便于扩展*/
public RecyclerView getRecyclerView() {
return vRecyclerView;
}
}
列表的分割线进行了自定义,主要是去除列表的最后一条分割线,目的是如果不显示加载更多时,最后不显示两条分割线
实现的接口类:
public interface IPullRecyclerView { /*上拉刷新操作*/ void onRefresh(); /*下拉加载更多*/ void onLoadMore(); }
代码没难度,不做具体介绍了
由于本人水平有限,代码的水平不高,但可以保证可以用,如果有新手想用可以直接把两个类复制到自己的代码中就可以直接使用了;
如果有问题请指出,谢谢!