package com.example.xrecyclerview; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; 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.util.SparseArray; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; /** * Created by jingbin on 2016/1/28. */ public class XRecyclerView extends RecyclerView { private LoadingListener mLoadingListener; private WrapAdapter mWrapAdapter; private SparseArray<View> mHeaderViews = new SparseArray<View>(); private SparseArray<View> mFootViews = new SparseArray<View>(); private boolean pullRefreshEnabled = true; private boolean loadingMoreEnabled = true; private YunRefreshHeader mRefreshHeader; private boolean isLoadingData; public int previousTotal; public boolean isnomore; private float mLastY = -1; private static final float DRAG_RATE = 1.75f; // 是否是额外添加FooterView private boolean isOther = false; public XRecyclerView(Context context) { this(context, null); } public XRecyclerView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public XRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { if (pullRefreshEnabled) { YunRefreshHeader refreshHeader = new YunRefreshHeader(context); mHeaderViews.put(0, refreshHeader); mRefreshHeader = refreshHeader; } LoadingMoreFooter footView = new LoadingMoreFooter(context); addFootView(footView, false); mFootViews.get(0).setVisibility(GONE); } /** * 改为公有。供外添加view使用,使用标识 * 注意:使用后不能使用 上拉加载,否则添加无效 * 使用时 isOther 传入 true,然后调用 noMoreLoading即可。 */ public void addFootView(final View view, boolean isOther) { mFootViews.clear(); mFootViews.put(0, view); this.isOther = isOther; } /** * 相当于加一个空白头布局: * 只有一个目的:为了滚动条显示在最顶端 * 因为默认加了刷新头布局,不处理滚动条会下移。 * 和 setPullRefreshEnabled(false) 一块儿使用 * 使用下拉头时,此方法不应被使用! */ public void clearHeader() { mHeaderViews.clear(); final float scale = getContext().getResources().getDisplayMetrics().density; int height = (int) (1.0f * scale + 0.5f); ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height); View view = new View(getContext()); view.setLayoutParams(params); mHeaderViews.put(0, view); } public void addHeaderView(View view) { if (pullRefreshEnabled && !(mHeaderViews.get(0) instanceof YunRefreshHeader)) { YunRefreshHeader refreshHeader = new YunRefreshHeader(getContext()); mHeaderViews.put(0, refreshHeader); mRefreshHeader = refreshHeader; } mHeaderViews.put(mHeaderViews.size(), view); } private void loadMoreComplete() { isLoadingData = false; View footView = mFootViews.get(0); if (previousTotal <= getLayoutManager().getItemCount()) { if (footView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) footView).setState(LoadingMoreFooter.STATE_COMPLETE); } else { footView.setVisibility(View.GONE); } } else { if (footView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) footView).setState(LoadingMoreFooter.STATE_NOMORE); } else { footView.setVisibility(View.GONE); } isnomore = true; } previousTotal = getLayoutManager().getItemCount(); } public void noMoreLoading() { isLoadingData = false; final View footView = mFootViews.get(0); isnomore = true; if (footView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) footView).setState(LoadingMoreFooter.STATE_NOMORE); } else { footView.setVisibility(View.GONE); } // 额外添加的footView if (isOther) { footView.setVisibility(View.VISIBLE); } } public void refreshComplete() { // mRefreshHeader.refreshComplate(); if (isLoadingData) { loadMoreComplete(); } else { mRefreshHeader.refreshComplate(); } } @Override public void setAdapter(Adapter adapter) { mWrapAdapter = new WrapAdapter(mHeaderViews, mFootViews, adapter); super.setAdapter(mWrapAdapter); adapter.registerAdapterDataObserver(mDataObserver); } @Override public void onScrollStateChanged(int state) { super.onScrollStateChanged(state); if (state == RecyclerView.SCROLL_STATE_IDLE && mLoadingListener != null && !isLoadingData && loadingMoreEnabled) { LayoutManager layoutManager = getLayoutManager(); int lastVisibleItemPosition; if (layoutManager instanceof GridLayoutManager) { lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition(); } else if (layoutManager instanceof StaggeredGridLayoutManager) { int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()]; ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into); lastVisibleItemPosition = findMax(into); } else { lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); } if (layoutManager.getChildCount() > 0 && lastVisibleItemPosition >= layoutManager.getItemCount() - 1 && layoutManager.getItemCount() > layoutManager.getChildCount() && !isnomore && mRefreshHeader.getState() < YunRefreshHeader.STATE_REFRESHING) { View footView = mFootViews.get(0); isLoadingData = true; if (footView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) footView).setState(LoadingMoreFooter.STATE_LOADING); } else { footView.setVisibility(View.VISIBLE); } if (isNetWorkConnected(getContext())) { mLoadingListener.onLoadMore(); } else { postDelayed(new Runnable() { @Override public void run() { mLoadingListener.onLoadMore(); } }, 1000); } } } } @Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); if (isOnTop() && pullRefreshEnabled) { mRefreshHeader.onMove(deltaY / DRAG_RATE); if (mRefreshHeader.getVisiableHeight() > 0 && mRefreshHeader.getState() < YunRefreshHeader.STATE_REFRESHING) { return false; } } break; default: mLastY = -1; // reset if (isOnTop() && pullRefreshEnabled) { if (mRefreshHeader.releaseAction()) { if (mLoadingListener != null) { mLoadingListener.onRefresh(); isnomore = false; previousTotal = 0; final View footView = mFootViews.get(0); if (footView instanceof LoadingMoreFooter) { if (footView.getVisibility() != View.GONE) { footView.setVisibility(View.GONE); } } } } } break; } return super.onTouchEvent(ev); } private int findMax(int[] lastPositions) { int max = lastPositions[0]; for (int value : lastPositions) { if (value > max) { max = value; } } return max; } private int findMin(int[] firstPositions) { int min = firstPositions[0]; for (int value : firstPositions) { if (value < min) { min = value; } } return min; } public boolean isOnTop() { if (mHeaderViews == null || mHeaderViews.size() == 0) { return false; } View view = mHeaderViews.get(0); if (view.getParent() != null) { return true; } else { return false; } } private final RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() { @Override public void onChanged() { mWrapAdapter.notifyDataSetChanged(); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount); } @Override public void onItemRangeChanged(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount); } @Override public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount); } @Override public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { mWrapAdapter.notifyItemMoved(fromPosition, toPosition); } }; public void setLoadingListener(LoadingListener listener) { mLoadingListener = listener; } public void setPullRefreshEnabled(boolean pullRefreshEnabled) { this.pullRefreshEnabled = pullRefreshEnabled; } public void setLoadingMoreEnabled(boolean loadingMoreEnabled) { this.loadingMoreEnabled = loadingMoreEnabled; if (!loadingMoreEnabled) { if (mFootViews != null) { mFootViews.remove(0); } } else { if (mFootViews != null) { LoadingMoreFooter footView = new LoadingMoreFooter(getContext()); addFootView(footView, false); } } } public void setLoadMoreGone() { if (mFootViews == null) { return; } View footView = mFootViews.get(0); if (footView != null && footView instanceof LoadingMoreFooter) { mFootViews.remove(0); } } public interface LoadingListener { void onRefresh(); void onLoadMore(); } /** * 检测网络是否可用 * * @param context * @return */ public static boolean isNetWorkConnected(Context context) { if (context != null) { ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); if (mNetworkInfo != null) { return mNetworkInfo.isAvailable(); } } return false; } public void reset() { isnomore = false; previousTotal = 0; final View footView = mFootViews.get(0); if (footView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) footView).reSet(); } } }