可上拉加载和下拉刷新的XRecyclerView

来源:互联网 发布:linux oracle 客户端 编辑:程序博客网 时间:2024/06/05 22:33
public class XRecyclerView extends RecyclerView {    private boolean isLoadingData = false;    private boolean isNoMore = false;    private int mRefreshProgressStyle = ProgressStyle.SysProgress;    private int mLoadingMoreProgressStyle = ProgressStyle.SysProgress;    private ArrayList<View> mHeaderViews = new ArrayList<>();    private WrapAdapter mWrapAdapter;    private float mLastY = -1;    private static final float DRAG_RATE = 3;    private LoadingListener mLoadingListener;    private ArrowRefreshHeader mRefreshHeader;    private boolean pullRefreshEnabled = true;    private boolean loadingMoreEnabled = true;    //下面的ItemViewType是保留值(ReservedItemViewType),如果用户的adapter与它们重复将会强制抛出异常。不过为了简化,我们检测到重复时对用户的提示是ItemViewType必须小于10000    private static final int TYPE_REFRESH_HEADER = 10000;//设置一个很大的数字,尽可能避免和用户的adapter冲突    private static final int TYPE_FOOTER = 10001;    private static final int HEADER_INIT_INDEX = 10002;    private static List<Integer> sHeaderTypes = new ArrayList<>();//每个header必须有不同的type,不然滚动的时候顺序会变化    private int mPageCount = 0;    //adapter没有数据的时候显示,类似于listView的emptyView    private View mEmptyView;    private View mFootView;    private final RecyclerView.AdapterDataObserver mDataObserver = new DataObserver();    private AppBarStateChangeListener.State appbarState = AppBarStateChangeListener.State.EXPANDED;    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();    }    private void init() {        if (pullRefreshEnabled) {            mRefreshHeader = new ArrowRefreshHeader(getContext());            mRefreshHeader.setProgressStyle(mRefreshProgressStyle);        }        LoadingMoreFooter footView = new LoadingMoreFooter(getContext());        footView.setProgressStyle(mLoadingMoreProgressStyle);        mFootView = footView;        mFootView.setVisibility(GONE);    }    public void addHeaderView(View view) {        sHeaderTypes.add(HEADER_INIT_INDEX + mHeaderViews.size());        mHeaderViews.add(view);        if (mWrapAdapter != null) {            mWrapAdapter.notifyDataSetChanged();        }    }    //根据header的ViewType判断是哪个header    private View getHeaderViewByType(int itemType) {        if(!isHeaderType(itemType)) {            return null;        }        return mHeaderViews.get(itemType - HEADER_INIT_INDEX);    }    //判断一个type是否为HeaderType    private boolean isHeaderType(int itemViewType) {        return  mHeaderViews.size() > 0 &&  sHeaderTypes.contains(itemViewType);    }    //判断是否是XRecyclerView保留的itemViewType    private boolean isReservedItemViewType(int itemViewType) {        if(itemViewType == TYPE_REFRESH_HEADER || itemViewType == TYPE_FOOTER || sHeaderTypes.contains(itemViewType)) {            return true;        } else {            return false;        }    }    public void setFootView(final View view) {        mFootView = view;    }    public void loadMoreComplete() {        isLoadingData = false;        if (mFootView instanceof LoadingMoreFooter) {            ((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_COMPLETE);        } else {            mFootView.setVisibility(View.GONE);        }    }    public void setNoMore(boolean noMore){        isLoadingData = false;        isNoMore = noMore;        if (mFootView instanceof LoadingMoreFooter) {            ((LoadingMoreFooter) mFootView).setState(isNoMore ? LoadingMoreFooter.STATE_NOMORE:LoadingMoreFooter.STATE_COMPLETE);        } else {            mFootView.setVisibility(View.GONE);        }    }    public void refresh() {        if (pullRefreshEnabled && mLoadingListener != null) {            mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING);            mLoadingListener.onRefresh();        }    }    public void reset(){        setNoMore(false);        loadMoreComplete();        refreshComplete();    }    public void refreshComplete() {        mRefreshHeader.refreshComplete();        setNoMore(false);    }    public void setRefreshHeader(ArrowRefreshHeader refreshHeader) {        mRefreshHeader = refreshHeader;    }    public void setPullRefreshEnabled(boolean enabled) {        pullRefreshEnabled = enabled;    }    public void setLoadingMoreEnabled(boolean enabled) {        loadingMoreEnabled = enabled;        if (!enabled) {            if (mFootView instanceof LoadingMoreFooter) {                ((LoadingMoreFooter)mFootView).setState(LoadingMoreFooter.STATE_COMPLETE);            }        }    }    public void setRefreshProgressStyle(int style) {        mRefreshProgressStyle = style;        if (mRefreshHeader != null) {            mRefreshHeader.setProgressStyle(style);        }    }    public void setLoadingMoreProgressStyle(int style) {        mLoadingMoreProgressStyle = style;        if (mFootView instanceof LoadingMoreFooter) {            ((LoadingMoreFooter) mFootView).setProgressStyle(style);        }    }    public void setArrowImageView(int resId) {        if (mRefreshHeader != null) {            mRefreshHeader.setArrowImageView(resId);        }    }    public void setEmptyView(View emptyView) {        this.mEmptyView = emptyView;        mDataObserver.onChanged();    }    public View getEmptyView() {        return mEmptyView;    }    @Override    public void setAdapter(Adapter adapter) {        mWrapAdapter = new WrapAdapter(adapter);        super.setAdapter(mWrapAdapter);        adapter.registerAdapterDataObserver(mDataObserver);        mDataObserver.onChanged();    }    //避免用户自己调用getAdapter() 引起的ClassCastException    @Override    public Adapter getAdapter() {        if(mWrapAdapter != null)            return mWrapAdapter.getOriginalAdapter();        else            return null;    }    @Override    public void setLayoutManager(LayoutManager layout) {        super.setLayoutManager(layout);        if(mWrapAdapter != null){            if (layout instanceof GridLayoutManager) {                final GridLayoutManager gridManager = ((GridLayoutManager) layout);                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {                    @Override                    public int getSpanSize(int position) {                        return (mWrapAdapter.isHeader(position) || mWrapAdapter.isFooter(position) || mWrapAdapter.isRefreshHeader(position))                                ? gridManager.getSpanCount() : 1;                    }                });            }        }    }    @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() < ArrowRefreshHeader.STATE_REFRESHING) {                isLoadingData = true;                if (mFootView instanceof LoadingMoreFooter) {                    ((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_LOADING);                } else {                    mFootView.setVisibility(View.VISIBLE);                }                mLoadingListener.onLoadMore();            }        }    }    @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 && appbarState == AppBarStateChangeListener.State.EXPANDED) {                    mRefreshHeader.onMove(deltaY / DRAG_RATE);                    if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {                        return false;                    }                }                break;            default:                mLastY = -1; // reset                if (isOnTop() && pullRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) {                    if (mRefreshHeader.releaseAction()) {                        if (mLoadingListener != null) {                            mLoadingListener.onRefresh();                        }                    }                }                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 boolean isOnTop() {        if (mRefreshHeader.getParent() != null) {            return true;        } else {            return false;        }    }    private class DataObserver extends RecyclerView.AdapterDataObserver {        @Override        public void onChanged() {            if (mWrapAdapter != null) {                mWrapAdapter.notifyDataSetChanged();            }            if (mWrapAdapter != null && mEmptyView != null) {                int emptyCount = 1 + mWrapAdapter.getHeadersCount();                if (loadingMoreEnabled) {                    emptyCount++;                }                if (mWrapAdapter.getItemCount() == emptyCount) {                    mEmptyView.setVisibility(View.VISIBLE);                    XRecyclerView.this.setVisibility(View.GONE);                } else {                    mEmptyView.setVisibility(View.GONE);                    XRecyclerView.this.setVisibility(View.VISIBLE);                }            }        }        @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);        }    };    private class WrapAdapter extends RecyclerView.Adapter<ViewHolder> {        private RecyclerView.Adapter adapter;        public WrapAdapter(RecyclerView.Adapter adapter) {            this.adapter = adapter;        }        public RecyclerView.Adapter getOriginalAdapter(){            return this.adapter;        }        public boolean isHeader(int position) {            return position >= 1 && position < mHeaderViews.size() + 1;        }        public boolean isFooter(int position) {            if(loadingMoreEnabled) {                return position == getItemCount() - 1;            }else {                return false;            }        }        public boolean isRefreshHeader(int position) {            return position == 0;        }        public int getHeadersCount() {            return mHeaderViews.size();        }        @Override        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            if (viewType == TYPE_REFRESH_HEADER) {                return new SimpleViewHolder(mRefreshHeader);            } else if (isHeaderType(viewType)) {                return new SimpleViewHolder(getHeaderViewByType(viewType));            } else if (viewType == TYPE_FOOTER) {                return new SimpleViewHolder(mFootView);            }            return adapter.onCreateViewHolder(parent, viewType);        }        @Override        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {            if (isHeader(position) || isRefreshHeader(position)) {                return;            }            int adjPosition = position - (getHeadersCount() + 1);            int adapterCount;            if (adapter != null) {                adapterCount = adapter.getItemCount();                if (adjPosition < adapterCount) {                    adapter.onBindViewHolder(holder, adjPosition);                }            }        }        // some times we need to override this        @Override        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position,List<Object> payloads) {            if (isHeader(position) || isRefreshHeader(position)) {                return;            }            int adjPosition = position - (getHeadersCount() + 1);            int adapterCount;            if (adapter != null) {                adapterCount = adapter.getItemCount();                if (adjPosition < adapterCount) {                    if(payloads.isEmpty()){                        adapter.onBindViewHolder(holder, adjPosition);                    }                    else{                        adapter.onBindViewHolder(holder, adjPosition,payloads);                    }                }            }        }        @Override        public int getItemCount() {            if(loadingMoreEnabled) {                if (adapter != null) {                    return getHeadersCount() + adapter.getItemCount() + 2;                } else {                    return getHeadersCount() + 2;                }            }else {                if (adapter != null) {                    return getHeadersCount() + adapter.getItemCount() + 1;                } else {                    return getHeadersCount() + 1;                }            }        }        @Override        public int getItemViewType(int position) {            int adjPosition = position - (getHeadersCount() + 1);            if (isRefreshHeader(position)) {                return TYPE_REFRESH_HEADER;            }            if (isHeader(position)) {                position = position - 1;                return sHeaderTypes.get(position);            }            if (isFooter(position)) {                return TYPE_FOOTER;            }            int adapterCount;            if (adapter != null) {                adapterCount = adapter.getItemCount();                if (adjPosition < adapterCount) {                    int type =  adapter.getItemViewType(adjPosition);                    if(isReservedItemViewType(type)) {                        throw new IllegalStateException("XRecyclerView require itemViewType in adapter should be less than 10000 " );                    }                    return type;                }            }            return 0;        }        @Override        public long getItemId(int position) {            if (adapter != null && position >= getHeadersCount() + 1) {                int adjPosition = position - (getHeadersCount() + 1);                if (adjPosition < adapter.getItemCount()) {                    return adapter.getItemId(adjPosition);                }            }            return -1;        }        @Override        public void onAttachedToRecyclerView(RecyclerView recyclerView) {            super.onAttachedToRecyclerView(recyclerView);            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();            if (manager instanceof GridLayoutManager) {                final GridLayoutManager gridManager = ((GridLayoutManager) manager);                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {                    @Override                    public int getSpanSize(int position) {                        return (isHeader(position) || isFooter(position) || isRefreshHeader(position))                                ? gridManager.getSpanCount() : 1;                    }                });            }            adapter.onAttachedToRecyclerView(recyclerView);        }        @Override        public void onDetachedFromRecyclerView(RecyclerView recyclerView) {            adapter.onDetachedFromRecyclerView(recyclerView);        }        @Override        public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {            super.onViewAttachedToWindow(holder);            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();            if (lp != null                    && lp instanceof StaggeredGridLayoutManager.LayoutParams                    && (isHeader(holder.getLayoutPosition()) ||isRefreshHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition()))) {                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;                p.setFullSpan(true);            }            adapter.onViewAttachedToWindow(holder);        }        @Override        public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {            adapter.onViewDetachedFromWindow(holder);        }        @Override        public void onViewRecycled(RecyclerView.ViewHolder holder) {            adapter.onViewRecycled(holder);        }        @Override        public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) {            return adapter.onFailedToRecycleView(holder);        }        @Override        public void unregisterAdapterDataObserver(AdapterDataObserver observer) {            adapter.unregisterAdapterDataObserver(observer);        }        @Override        public void registerAdapterDataObserver(AdapterDataObserver observer) {            adapter.registerAdapterDataObserver(observer);        }        private class SimpleViewHolder extends RecyclerView.ViewHolder {            public SimpleViewHolder(View itemView) {                super(itemView);            }        }    }    public void setLoadingListener(LoadingListener listener) {        mLoadingListener = listener;    }    public interface LoadingListener {        void onRefresh();        void onLoadMore();    }    @Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        //解决和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;                    }                });            }        }    }    public class DividerItemDecoration extends RecyclerView.ItemDecoration {        private Drawable mDivider;        private int mOrientation;        /**         * Sole constructor. Takes in a {@link Drawable} to be used as the interior         * divider.         *         * @param divider A divider {@code Drawable} to be drawn on the RecyclerView         */        public DividerItemDecoration(Drawable divider) {            mDivider = divider;        }        /**         * Draws horizontal or vertical dividers onto the parent RecyclerView.         *         * @param canvas The {@link Canvas} onto which dividers will be drawn         * @param parent The RecyclerView onto which dividers are being added         * @param state The current RecyclerView.State of the RecyclerView         */        @Override        public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {            if (mOrientation == LinearLayoutManager.HORIZONTAL) {                drawHorizontalDividers(canvas, parent);            } else if (mOrientation == LinearLayoutManager.VERTICAL) {                drawVerticalDividers(canvas, parent);            }        }        /**         * Determines the size and location of offsets between items in the parent         * RecyclerView.         *         * @param outRect The {@link Rect} of offsets to be added around the child         *                view         * @param view The child view to be decorated with an offset         * @param parent The RecyclerView onto which dividers are being added         * @param state The current RecyclerView.State of the RecyclerView         */        @Override        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {            super.getItemOffsets(outRect, view, parent, state);            if (parent.getChildAdapterPosition(view) <= mWrapAdapter.getHeadersCount() + 1) {                return;            }            mOrientation = ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();            if (mOrientation == LinearLayoutManager.HORIZONTAL) {                outRect.left = mDivider.getIntrinsicWidth();            } else if (mOrientation == LinearLayoutManager.VERTICAL) {                outRect.top = mDivider.getIntrinsicHeight();            }        }        /**         * Adds dividers to a RecyclerView with a LinearLayoutManager or its         * subclass oriented horizontally.         *         * @param canvas The {@link Canvas} onto which horizontal dividers will be         *               drawn         * @param parent The RecyclerView onto which horizontal dividers are being         *               added         */        private void drawHorizontalDividers(Canvas canvas, RecyclerView parent) {            int parentTop = parent.getPaddingTop();            int parentBottom = parent.getHeight() - parent.getPaddingBottom();            int childCount = parent.getChildCount();            for (int i = 0; i < childCount - 1; i++) {                View child = parent.getChildAt(i);                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();                int parentLeft = child.getRight() + params.rightMargin;                int parentRight = parentLeft + mDivider.getIntrinsicWidth();                mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);                mDivider.draw(canvas);            }        }        /**         * Adds dividers to a RecyclerView with a LinearLayoutManager or its         * subclass oriented vertically.         *         * @param canvas The {@link Canvas} onto which vertical dividers will be         *               drawn         * @param parent The RecyclerView onto which vertical dividers are being         *               added         */        private void drawVerticalDividers(Canvas canvas, RecyclerView parent) {            int parentLeft = parent.getPaddingLeft();            int parentRight = parent.getWidth() - parent.getPaddingRight();            int childCount = parent.getChildCount();            for (int i = 0; i < childCount - 1; i++) {                View child = parent.getChildAt(i);                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();                int parentTop = child.getBottom() + params.bottomMargin;                int parentBottom = parentTop + mDivider.getIntrinsicHeight();                mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);                mDivider.draw(canvas);            }        }    }}


布局

<com.jcodecraeer.xrecyclerview.XRecyclerView    android:id="@+id/xrv_list"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:scrollbarSize="0.5dp"    android:scrollbars="vertical" />



原创粉丝点击