/**
* author:xc
* date: 2018/7/25
* desc: 支持下拉刷新上拉加载更多的RecycleView
*/
public class PullLoadMoreRecyclerView extends LinearLayout {
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mSwipeRefreshLayout;
private PullLoadMoreListener mPullLoadMoreListener;
private boolean hasMore = true;
private boolean isRefresh = false;
private boolean isLoadMore = false;
private boolean pullRefreshEnable = true;
private boolean pushRefreshEnable = true;
private View mFooterView;
private Context mContext;
private TextView loadMoreText;
private LinearLayout loadMoreLayout;
public PullLoadMoreRecyclerView(Context context) {
super(context);
initView(context);
}
public PullLoadMoreRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
mContext = context;
View view = LayoutInflater.from(context).inflate(R.layout.pull_loadmore_layout, null);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_green_dark, android.R.color.holo_blue_dark, android.R.color.holo_orange_dark);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayoutOnRefresh(this));
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
mRecyclerView.setHorizontalFadingEdgeEnabled(true);
mRecyclerView.setVerticalScrollBarEnabled(true);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addOnScrollListener(new RecyclerViewOnScroll(this));
mRecyclerView.setOnTouchListener(new onTouchRecyclerView());
mFooterView = view.findViewById(R.id.footerView);
loadMoreLayout = (LinearLayout) view.findViewById(R.id.loadMoreLayout);
loadMoreText = (TextView) view.findViewById(R.id.loadMoreText);
mFooterView.setVisibility(View.GONE);
this.addView(view);
}
/**
* LinearLayoutManager
*/
public void setLinearLayout() {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
}
public void setHORIZONTALLinearLayout() {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
}
/**
* GridLayoutManager
*/
public void setGridLayout(int spanCount) {
GridLayoutManager gridLayoutManager = new WrapContentLinearLayoutManager(mContext, spanCount);
gridLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(gridLayoutManager);
}
public class WrapContentLinearLayoutManager extends GridLayoutManager {
public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public WrapContentLinearLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}
public WrapContentLinearLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
/**
* StaggeredGridLayoutManager
*/
public void setStaggeredGridLayout(int spanCount) {
StaggeredGridLayoutManager staggeredGridLayoutManager =
new StaggeredGridLayoutManager(spanCount, LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(staggeredGridLayoutManager);
}
public RecyclerView.LayoutManager getLayoutManager() {
return mRecyclerView.getLayoutManager();
}
public RecyclerView getRecyclerView() {
return mRecyclerView;
}
public void setItemAnimator(RecyclerView.ItemAnimator animator) {
mRecyclerView.setItemAnimator(animator);
}
public void addItemDecoration(RecyclerView.ItemDecoration decor, int index) {
mRecyclerView.addItemDecoration(decor, index);
}
public void addItemDecoration(RecyclerView.ItemDecoration decor) {
mRecyclerView.addItemDecoration(decor);
}
public void scrollToTop() {
mRecyclerView.scrollToPosition(0);
}
public void setAdapter(RecyclerView.Adapter adapter) {
if (adapter != null) {
mRecyclerView.setAdapter(adapter);
}
}
public void setPullRefreshEnable(boolean enable) {
pullRefreshEnable = enable;
setSwipeRefreshEnable(enable);
}
public boolean getPullRefreshEnable() {
return pullRefreshEnable;
}
public void setSwipeRefreshEnable(boolean enable) {
mSwipeRefreshLayout.setEnabled(enable);
}
public boolean getSwipeRefreshEnable() {
return mSwipeRefreshLayout.isEnabled();
}
public void setColorSchemeResources(int... colorResIds) {
mSwipeRefreshLayout.setColorSchemeResources(colorResIds);
}
public SwipeRefreshLayout getSwipeRefreshLayout() {
return mSwipeRefreshLayout;
}
public void setRefreshing(final boolean isRefreshing) {
mSwipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
if (pullRefreshEnable)
mSwipeRefreshLayout.setRefreshing(isRefreshing);
}
});
}
/**
* Solve IndexOutOfBoundsException exception
*/
public class onTouchRecyclerView implements OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
return isRefresh || isLoadMore;
}
}
public boolean getPushRefreshEnable() {
return pushRefreshEnable;
}
public void setPushRefreshEnable(boolean pushRefreshEnable) {
this.pushRefreshEnable = pushRefreshEnable;
}
public LinearLayout getFooterViewLayout() {
return loadMoreLayout;
}
public void setFooterViewBackgroundColor(int color) {
loadMoreLayout.setBackgroundColor(ContextCompat.getColor(mContext, color));
}
public void setFooterViewText(CharSequence text) {
loadMoreText.setText(text);
}
public void setFooterViewText(int resid) {
loadMoreText.setText(resid);
}
public void setFooterViewTextColor(int color) {
loadMoreText.setTextColor(ContextCompat.getColor(mContext, color));
}
public void refresh() {
if (mPullLoadMoreListener != null) {
mPullLoadMoreListener.onRefresh();
}
}
public void loadMore() {
if (mPullLoadMoreListener != null && hasMore) {
mFooterView.animate()
.translationY(0)
.setDuration(300)
.setInterpolator(new AccelerateDecelerateInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mFooterView.setVisibility(View.VISIBLE);
}
})
.start();
invalidate();
mPullLoadMoreListener.onLoadMore();
}
}
public void setPullLoadMoreCompleted() {
isRefresh = false;
setRefreshing(false);
isLoadMore = false;
mFooterView.animate()
.translationY(mFooterView.getHeight())
.setDuration(300)
.setInterpolator(new AccelerateDecelerateInterpolator())
.start();
}
public void setOnPullLoadMoreListener(PullLoadMoreListener listener) {
mPullLoadMoreListener = listener;
}
public boolean isLoadMore() {
return isLoadMore;
}
public void setIsLoadMore(boolean isLoadMore) {
this.isLoadMore = isLoadMore;
}
public boolean isRefresh() {
return isRefresh;
}
public void setIsRefresh(boolean isRefresh) {
this.isRefresh = isRefresh;
}
public boolean isHasMore() {
return hasMore;
}
public void setHasMore(boolean hasMore) {
this.hasMore = hasMore;
}
public interface PullLoadMoreListener {
void onRefresh();
void onLoadMore();
}
private class SwipeRefreshLayoutOnRefresh implements SwipeRefreshLayout.OnRefreshListener {
private PullLoadMoreRecyclerView mPullLoadMoreRecyclerView;
public SwipeRefreshLayoutOnRefresh(PullLoadMoreRecyclerView pullLoadMoreRecyclerView) {
this.mPullLoadMoreRecyclerView = pullLoadMoreRecyclerView;
}
@Override
public void onRefresh() {
if (!mPullLoadMoreRecyclerView.isRefresh()) {
mPullLoadMoreRecyclerView.setIsRefresh(true);
mPullLoadMoreRecyclerView.refresh();
}
}
}
private class RecyclerViewOnScroll extends RecyclerView.OnScrollListener {
private PullLoadMoreRecyclerView mPullLoadMoreRecyclerView;
public RecyclerViewOnScroll(PullLoadMoreRecyclerView pullLoadMoreRecyclerView) {
this.mPullLoadMoreRecyclerView = pullLoadMoreRecyclerView;
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int lastItem = 0;
int firstItem = 0;
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
int totalItemCount = layoutManager.getItemCount();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = ((GridLayoutManager) layoutManager);
firstItem = gridLayoutManager.findFirstCompletelyVisibleItemPosition();
//Position to find the final item of the current LayoutManager
lastItem = gridLayoutManager.findLastCompletelyVisibleItemPosition();
if (lastItem == -1) lastItem = gridLayoutManager.findLastVisibleItemPosition();
} else if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager linearLayoutManager = ((LinearLayoutManager) layoutManager);
firstItem = linearLayoutManager.findFirstCompletelyVisibleItemPosition();
lastItem = linearLayoutManager.findLastCompletelyVisibleItemPosition();
if (lastItem == -1) lastItem = linearLayoutManager.findLastVisibleItemPosition();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
StaggeredGridLayoutManager staggeredGridLayoutManager = ((StaggeredGridLayoutManager) layoutManager);
// since may lead to the final item has more than one StaggeredGridLayoutManager the particularity of the so here that is an array
// this array into an array of position and then take the maximum value that is the last show the position value
int[] lastPositions = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(lastPositions);
lastItem = findMax(lastPositions);
firstItem = staggeredGridLayoutManager.findFirstVisibleItemPositions(lastPositions)[0];
}
if (firstItem == 0 || firstItem == RecyclerView.NO_POSITION) {
if (mPullLoadMoreRecyclerView.getPullRefreshEnable())
mPullLoadMoreRecyclerView.setSwipeRefreshEnable(true);
} else {
mPullLoadMoreRecyclerView.setSwipeRefreshEnable(false);
}
if (mPullLoadMoreRecyclerView.getPushRefreshEnable()
&& !mPullLoadMoreRecyclerView.isRefresh()
&& mPullLoadMoreRecyclerView.isHasMore()
&& (lastItem == totalItemCount - 1)
&& !mPullLoadMoreRecyclerView.isLoadMore()
&& (dx > 0 || dy > 0)) {
mPullLoadMoreRecyclerView.setIsLoadMore(true);
mPullLoadMoreRecyclerView.loadMore();
}
}
//To find the maximum value in the array
private int findMax(int[] lastPositions) {
int max = lastPositions[0];
for (int value : lastPositions) {
if (value > max) {
max = value;
}
}
return max;
}
}
}
以下是XML布局代码
pull_loadmore_layout:
footer_layout:
自定义RecyclerViewAdapter:
/**
* author:xc
* date: 2018/12/12
* desc:自定义RecyclerViewAdapter
*/
public abstract class MyBaseRecycleViewAdapter extends RecyclerView.Adapter {
private Context mContext;
protected List mDataList = new ArrayList<>();
private LayoutInflater mInflater;
public MyBaseRecycleViewAdapter(Context context) {
mContext = context;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setDataList(Collection list) {
this.mDataList.clear();
this.mDataList.addAll(list);
notifyDataSetChanged();
}
public void addAllData(Collection list) {
int lastIndex = this.mDataList.size();
if (this.mDataList.addAll(list)) {
notifyItemRangeInserted(lastIndex, list.size());
}
}
public void remove(int position) {
this.mDataList.remove(position);
notifyItemRemoved(position);
if (position != (getDataList().size())) { // 如果移除的是最后一个,忽略
notifyItemRangeChanged(position, this.mDataList.size() - position);
}
}
public void clearData() {
this.mDataList.clear();
}
@Override
public SuperViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(getLayoutId(), parent, false);
AutoUtils.autoSize(itemView);
return new SuperViewHolder(itemView);
}
@Override
public void onBindViewHolder(SuperViewHolder holder, int position) {
onBindItemHolder(holder, position);
}
@Override
public int getItemCount() {
return mDataList.size();
}
public List getDataList() {
return mDataList;
}
public abstract int getLayoutId();
public abstract void onBindItemHolder(SuperViewHolder holder, int position);
}
ViewHolder基类:
/**
* ViewHolder基类
*/
public class SuperViewHolder extends RecyclerView.ViewHolder {
private SparseArray views;
public SuperViewHolder(View itemView) {
super(itemView);
this.views = new SparseArray<>();
}
@SuppressWarnings("unchecked")
public T getView(int viewId) {
View view = views.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
views.put(viewId, view);
}
return (T) view;
}
}