package com.github.jdsjlzx.recyclerview; import android.content.Context; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CoordinatorLayout; import android.support.v4.content.ContextCompat; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.AttributeSet; import android.view.View; import android.view.ViewParent; import com.github.jdsjlzx.interfaces.ILoadMoreFooter; import com.github.jdsjlzx.interfaces.OnLoadMoreListener; import com.github.jdsjlzx.interfaces.OnNetWorkErrorListener; import com.github.jdsjlzx.view.LoadingFooter; /** * * @author Lzx * @created 2016/9/9 16:45 * */ public class LuRecyclerView extends RecyclerView { private boolean mLoadMoreEnabled = true; private boolean mRefreshing = false;//是否正在下拉刷新 private boolean mLoadingData = false;//是否正在加载数据 private boolean flag = false;//标记是否setAdapter private OnLoadMoreListener mLoadMoreListener; private LScrollListener mLScrollListener; private ILoadMoreFooter mLoadMoreFooter; private View mEmptyView; private View mFootView; private final RecyclerView.AdapterDataObserver mDataObserver = new DataObserver(); private int mPageSize = 10; //一次网络请求默认数量 private LuRecyclerViewAdapter mWrapAdapter; private boolean isNoMore = false; //scroll variables begin /** * 当前RecyclerView类型 */ protected LayoutManagerType layoutManagerType; /** * 最后一个的位置 */ private int[] lastPositions; /** * 最后一个可见的item的位置 */ private int lastVisibleItemPosition; /** * 当前滑动的状态 */ private int currentScrollState = 0; /** * 触发在上下滑动监听器的容差距离 */ private static final int HIDE_THRESHOLD = 20; /** * 滑动的距离 */ private int mDistance = 0; /** * 是否需要监听控制 */ private boolean mIsScrollDown = true; /** * Y轴移动的实际距离(最顶部为0) */ private int mScrolledYDistance = 0; /** * X轴移动的实际距离(最左侧为0) */ private int mScrolledXDistance = 0; //scroll variables end private AppBarStateChangeListener.State appbarState = AppBarStateChangeListener.State.EXPANDED; public LuRecyclerView(Context context) { this(context, null); } public LuRecyclerView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public LuRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { if (mLoadMoreEnabled) { setLoadMoreFooter(new LoadingFooter(getContext().getApplicationContext())); } } @Override public void setAdapter(Adapter adapter) { if (mWrapAdapter != null && mDataObserver != null) { mWrapAdapter.getInnerAdapter().unregisterAdapterDataObserver(mDataObserver); } mWrapAdapter = (LuRecyclerViewAdapter) adapter; super.setAdapter(mWrapAdapter); mWrapAdapter.getInnerAdapter().registerAdapterDataObserver(mDataObserver); mDataObserver.onChanged(); if (mLoadMoreEnabled && mWrapAdapter.getFooterViewsCount()==0) { mWrapAdapter.addFooterView(mFootView); } } private class DataObserver extends RecyclerView.AdapterDataObserver { @Override public void onChanged() { Adapter<?> adapter = getAdapter(); if (adapter instanceof LRecyclerViewAdapter) { LRecyclerViewAdapter lRecyclerViewAdapter = (LRecyclerViewAdapter) adapter; if (lRecyclerViewAdapter.getInnerAdapter() != null && mEmptyView != null) { int count = lRecyclerViewAdapter.getInnerAdapter().getItemCount(); if (count == 0) { mEmptyView.setVisibility(View.VISIBLE); LuRecyclerView.this.setVisibility(View.GONE); } else { mEmptyView.setVisibility(View.GONE); LuRecyclerView.this.setVisibility(View.VISIBLE); } } } else { if (adapter != null && mEmptyView != null) { if (adapter.getItemCount() == 0) { mEmptyView.setVisibility(View.VISIBLE); LuRecyclerView.this.setVisibility(View.GONE); } else { mEmptyView.setVisibility(View.GONE); LuRecyclerView.this.setVisibility(View.VISIBLE); } } } if (mWrapAdapter != null) { mWrapAdapter.notifyDataSetChanged(); if(mWrapAdapter.getInnerAdapter().getItemCount() < mPageSize ) { mFootView.setVisibility(GONE); } } } @Override public void onItemRangeChanged(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeChanged(positionStart + mWrapAdapter.getHeaderViewsCount() + 1, itemCount); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeInserted(positionStart + mWrapAdapter.getHeaderViewsCount() + 1, itemCount); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeRemoved(positionStart + mWrapAdapter.getHeaderViewsCount() + 1, itemCount); if(mWrapAdapter.getInnerAdapter().getItemCount() < mPageSize ) { mFootView.setVisibility(GONE); } } @Override public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { int headerViewsCountCount = mWrapAdapter.getHeaderViewsCount(); mWrapAdapter.notifyItemRangeChanged(fromPosition + headerViewsCountCount + 1, toPosition + headerViewsCountCount + 1 + itemCount); } } private int findMax(int[] lastPositions) { int max = lastPositions[0]; for (int value : lastPositions) { if (value > max) { max = value; } } return max; } /** * set view when no content item * * @param emptyView visiable view when items is empty */ public void setEmptyView(View emptyView) { this.mEmptyView = emptyView; mDataObserver.onChanged(); } public void setRefreshing(boolean refreshing) { mRefreshing = refreshing; } /** * * @param pageSize 一页加载的数量 */ public void refreshComplete(int pageSize) { this.mPageSize = pageSize; if (mRefreshing) { isNoMore = false; mRefreshing = false; if(mWrapAdapter.getInnerAdapter().getItemCount() < pageSize) { mFootView.setVisibility(GONE); } } else if (mLoadingData) { mLoadingData = false; mLoadMoreFooter.onComplete(); } } /** * 设置是否已加载全部 * @param noMore */ public void setNoMore(boolean noMore){ mLoadingData = false; isNoMore = noMore; if(isNoMore) { mLoadMoreFooter.onNoMore(); } else { mLoadMoreFooter.onComplete(); } } /** * 设置自定义的footerview */ public void setLoadMoreFooter(ILoadMoreFooter loadMoreFooter) { this.mLoadMoreFooter = loadMoreFooter; mFootView = loadMoreFooter.getFootView(); mFootView.setVisibility(GONE); } /** * 到底加载是否可用 */ public void setLoadMoreEnabled(boolean enabled) { if(mWrapAdapter == null){ throw new NullPointerException("mWrapAdapter cannot be null, please make sure the variable mWrapAdapter have been initialized."); } mLoadMoreEnabled = enabled; if (!enabled) { if (null != mWrapAdapter) { mWrapAdapter.removeFooterView(); } else { mLoadMoreFooter.onReset(); } } } public void setLoadingMoreProgressStyle(int style) { if (mLoadMoreFooter != null && mLoadMoreFooter instanceof LoadingFooter) { ((LoadingFooter) mLoadMoreFooter).setProgressStyle(style); } } public void setOnLoadMoreListener(OnLoadMoreListener listener) { mLoadMoreListener = listener; } public void setOnNetWorkErrorListener(final OnNetWorkErrorListener listener) { final LoadingFooter loadingFooter = ((LoadingFooter) mFootView); loadingFooter.setState(LoadingFooter.State.NetWorkError); loadingFooter.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mLoadMoreFooter.onLoading(); listener.reload(); } }); } public void setFooterViewHint(String loading, String noMore, String noNetWork) { if (mLoadMoreFooter != null && mLoadMoreFooter instanceof LoadingFooter) { LoadingFooter loadingFooter = ((LoadingFooter) mLoadMoreFooter); loadingFooter.setLoadingHint(loading); loadingFooter.setNoMoreHint(noMore); loadingFooter.setNoNetWorkHint(noNetWork); } } /** * 设置Footer文字颜色 * @param indicatorColor * @param hintColor * @param backgroundColor */ public void setFooterViewColor(int indicatorColor, int hintColor, int backgroundColor) { if (mLoadMoreFooter != null && mLoadMoreFooter instanceof LoadingFooter) { LoadingFooter loadingFooter = ((LoadingFooter) mLoadMoreFooter); loadingFooter.setIndicatorColor(ContextCompat.getColor(getContext(),indicatorColor)); loadingFooter.setHintTextColor(hintColor); loadingFooter.setViewBackgroundColor(backgroundColor); } } public void setLScrollListener(LScrollListener listener) { mLScrollListener = listener; } public interface LScrollListener { void onScrollUp();//scroll down to up void onScrollDown();//scroll from up to down void onScrolled(int distanceX, int distanceY);// moving state,you can get the move distance void onScrollStateChanged(int state); } @Override public void onScrolled(int dx, int dy) { super.onScrolled(dx, dy); int firstVisibleItemPosition = 0; RecyclerView.LayoutManager layoutManager = getLayoutManager(); if (layoutManagerType == null) { if (layoutManager instanceof LinearLayoutManager) { layoutManagerType = LayoutManagerType.LinearLayout; } else if (layoutManager instanceof GridLayoutManager) { layoutManagerType = LayoutManagerType.GridLayout; } else if (layoutManager instanceof StaggeredGridLayoutManager) { layoutManagerType = LayoutManagerType.StaggeredGridLayout; } else { throw new RuntimeException( "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager"); } } switch (layoutManagerType) { case LinearLayout: firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); break; case GridLayout: firstVisibleItemPosition = ((GridLayoutManager) layoutManager).findFirstVisibleItemPosition(); lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition(); break; case StaggeredGridLayout: StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager; if (lastPositions == null) { lastPositions = new int[staggeredGridLayoutManager.getSpanCount()]; } staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions); lastVisibleItemPosition = findMax(lastPositions); staggeredGridLayoutManager.findFirstCompletelyVisibleItemPositions(lastPositions); firstVisibleItemPosition = findMax(lastPositions); break; } // 根据类型来计算出第一个可见的item的位置,由此判断是否触发到底部的监听器 // 计算并判断当前是向上滑动还是向下滑动 calculateScrollUpOrDown(firstVisibleItemPosition, dy); // 移动距离超过一定的范围,我们监听就没有啥实际的意义了 mScrolledXDistance += dx; mScrolledYDistance += dy; mScrolledXDistance = (mScrolledXDistance < 0) ? 0 : mScrolledXDistance; mScrolledYDistance = (mScrolledYDistance < 0) ? 0 : mScrolledYDistance; if (mIsScrollDown && (dy == 0)) { mScrolledYDistance = 0; } //Be careful in here if (null != mLScrollListener) { mLScrollListener.onScrolled(mScrolledXDistance, mScrolledYDistance); } } @Override public void onScrollStateChanged(int state) { super.onScrollStateChanged(state); currentScrollState = state; if (mLScrollListener != null) { mLScrollListener.onScrollStateChanged(state); } if (mLoadMoreListener != null && mLoadMoreEnabled) { if (currentScrollState == RecyclerView.SCROLL_STATE_IDLE) { RecyclerView.LayoutManager layoutManager = getLayoutManager(); int visibleItemCount = layoutManager.getChildCount(); int totalItemCount = layoutManager.getItemCount(); if (visibleItemCount > 0 && lastVisibleItemPosition >= totalItemCount - 1 && totalItemCount > visibleItemCount && !isNoMore && !mRefreshing) { mFootView.setVisibility(View.VISIBLE); if (mLoadingData) { return; } else { mLoadingData = true; mLoadMoreFooter.onLoading(); mLoadMoreListener.onLoadMore(); } } } } } /** * 计算当前是向上滑动还是向下滑动 */ private void calculateScrollUpOrDown(int firstVisibleItemPosition, int dy) { if (null != mLScrollListener) { if (firstVisibleItemPosition == 0) { if (!mIsScrollDown) { mIsScrollDown = true; mLScrollListener.onScrollDown(); } } else { if (mDistance > HIDE_THRESHOLD && mIsScrollDown) { mIsScrollDown = false; mLScrollListener.onScrollUp(); mDistance = 0; } else if (mDistance < -HIDE_THRESHOLD && !mIsScrollDown) { mIsScrollDown = true; mLScrollListener.onScrollDown(); mDistance = 0; } } } if ((mIsScrollDown && dy > 0) || (!mIsScrollDown && dy < 0)) { mDistance += dy; } } public enum LayoutManagerType { LinearLayout, StaggeredGridLayout, GridLayout } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); //解决LRecyclerView与CollapsingToolbarLayout滑动冲突的问题 AppBarLayout appBarLayout = null; ViewParent p = getParent(); while (p != null) { if (p instanceof CoordinatorLayout) { break; } p = p.getParent(); } if(p instanceof CoordinatorLayout) { CoordinatorLayout coordinatorLayout = (CoordinatorLayout)p; final int childCount = coordinatorLayout.getChildCount(); for (int i = childCount - 1; i >= 0; i--) { final View child = coordinatorLayout.getChildAt(i); if(child instanceof AppBarLayout) { appBarLayout = (AppBarLayout)child; break; } } if(appBarLayout != null) { appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { @Override public void onStateChanged(AppBarLayout appBarLayout, State state) { appbarState = state; } }); } } } }