zoukankan      html  css  js  c++  java
  • Android 实现下拉刷新和上拉加载更多的RECYCLERVIEW和SCROLLVIEW

    PullRefreshRecyclerView.java
    /**
     * 类说明:下拉刷新上拉加载更多的RecyclerView
     * Author: gaobaiq
     * Date: 2016/5/9 18:09
     */
    public class PullRefreshRecyclerView extends PullRefreshView {
    
        /**
         * 内置的RecyclerView;
         */
        private RecyclerView mRecyclerView;
    
        /**
         * 可见的最后一个item
         */
        private int lastVisibleItem;
    
        /**
         * 可见的第一个item
         */
        private int firstVisibleItem;
    
        /**
         * 空数据提示布局容器
         */
        private LinearLayout mEmptyLayout;
    
        /**
         * 是否自动上拉刷新
         */
        private boolean isAutomaticUp = false;
    
        public PullRefreshRecyclerView(Context context) {
            this(context, null);
        }
    
        public PullRefreshRecyclerView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public PullRefreshRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mRecyclerView = new RecyclerView(context);
            mRecyclerView.setClipToPadding(false);
            this.addView(mRecyclerView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
            initListener();
        }
    
        private void initListener() {
            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    if (isAutomaticUp && newState == RecyclerView.SCROLL_STATE_IDLE && pullUp()) {
                        triggerPullUpRefresh();
                    }
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    getVisibleItem();
                }
            });
        }
    
        private int getMax(int[] arr) {
            int max = arr[0];
            for (int x = 1; x < arr.length; x++) {
                if (arr[x] > max)
                    max = arr[x];
            }
            return max;
        }
    
        private int getMin(int[] arr) {
            int min = arr[0];
            for (int x = 1; x < arr.length; x++) {
                if (arr[x] < min)
                    min = arr[x];
            }
            return min;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    getVisibleItem();
                    break;
            }
            return super.onTouchEvent(event);
        }
    
        /**
         * 获取当前第一个显示的item 和 最后一个显示的item.
         */
        private void getVisibleItem() {
            RecyclerView.LayoutManager layout = mRecyclerView.getLayoutManager();
    
            if (layout != null) {
                if (layout instanceof LinearLayoutManager) {
                    lastVisibleItem = ((LinearLayoutManager) layout).findLastVisibleItemPosition();
                    firstVisibleItem = ((LinearLayoutManager) layout).findFirstVisibleItemPosition();
                } else if (layout instanceof GridLayoutManager) {
                    lastVisibleItem = ((GridLayoutManager) layout).findLastVisibleItemPosition();
                    firstVisibleItem = ((GridLayoutManager) layout).findFirstVisibleItemPosition();
                } else if (layout instanceof StaggeredGridLayoutManager) {
                    int[] lastPositions = new int[((StaggeredGridLayoutManager) layout).getSpanCount()];
                    ((StaggeredGridLayoutManager) layout).findLastVisibleItemPositions(lastPositions);
                    lastVisibleItem = getMax(lastPositions);
                    int[] firstPositions = new int[((StaggeredGridLayoutManager) layout).getSpanCount()];
                    ((StaggeredGridLayoutManager) layout).findFirstVisibleItemPositions(firstPositions);
                    firstVisibleItem = getMin(lastPositions);
                }
            }
        }
    
        @Override
        protected boolean isChildBottom(ViewGroup viewGroup) {
    
            boolean resultValue = false;
            int childNum = viewGroup.getChildCount();
    
            if (childNum == 0 || mRecyclerView.getChildCount() == 0) {
                resultValue = false;
            } else {
    
                if (mRecyclerView.equals(getChildAt(2)) && lastVisibleItem != mRecyclerView.getAdapter().getItemCount() - 1) {
                    return false;
                }
    
                View view = viewGroup.getChildAt(childNum - 1);
                int bottomMargin = ((MarginLayoutParams) view.getLayoutParams()).bottomMargin;
                if (view.getBottom() + bottomMargin + viewGroup.getPaddingBottom() <= getHeight()) {
                    resultValue = true;
                }
            }
            return resultValue;
        }
    
        @Override
        protected boolean isChildTop(ViewGroup viewGroup) {
            boolean resultValue = false;
            int childNum = viewGroup.getChildCount();
    
            if (childNum == 0) {
                resultValue = true;
            } else {
                if (mRecyclerView.equals(getChildAt(2)) && firstVisibleItem != 0) {
                    return false;
                }
    
                View view = viewGroup.getChildAt(0);
                int topMargin = ((MarginLayoutParams) view.getLayoutParams()).topMargin;
    
                if (view.getTop() - topMargin - viewGroup.getPaddingTop() >= 0) {
                    resultValue = true;
                }
            }
            return resultValue;
        }
    
        @Override
        public void triggerPullDownRefresh() {
            mRecyclerView.scrollToPosition(0);
            super.triggerPullDownRefresh();
        }
    
        /**
         * 设置空布局
         *
         * @param emptyView
         * @param layoutGravity 空布局在父布局的方向
         */
        public void setEmptyView(View emptyView, int layoutGravity) {
            if (mEmptyLayout == null) {
                initEmptyLayout();
            }
            mEmptyLayout.setGravity(layoutGravity);
            mEmptyLayout.addView(emptyView);
        }
    
        /**
         * 显示空布局
         */
        public void showEmptyView() {
            if (mEmptyLayout != null && mEmptyLayout.getParent() == null) {
                addView(mEmptyLayout, 2);
            }
            if (mRecyclerView.getParent() != null) {
                removeView(mRecyclerView);
            }
        }
    
        /**
         * 隐藏空布局
         */
        public void hideEmptyView() {
            if (mRecyclerView.getParent() == null) {
                addView(mRecyclerView, 2);
            }
            if (mEmptyLayout != null && mEmptyLayout.getParent() != null) {
                removeView(mEmptyLayout);
            }
        }
    
        private void initEmptyLayout() {
            mEmptyLayout = new LinearLayout(mContext);
            LayoutParams lp = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
            mEmptyLayout.setLayoutParams(lp);
            mEmptyLayout.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return true;
                }
            });
        }
    
        /**
         * 滑动到底部时,是否自动触发上拉加载更多。
         *
         * @param isAutomaticUp
         */
        public void isAutomaticUp(boolean isAutomaticUp) {
            this.isAutomaticUp = isAutomaticUp;
        }
    
        //提供获取内置RecyclerView的方法
        public RecyclerView getRecyclerView() {
            return mRecyclerView;
        }
    
        //********* 提供一系列对内置RecyclerView的操作方法 *********//
    
        public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {
            mRecyclerView.setLayoutManager(layoutManager);
        }
    
        public void setAdapter(RecyclerView.Adapter adapter) {
            mRecyclerView.setAdapter(adapter);
        }
    
        public void setItemAnimator(RecyclerView.ItemAnimator animator) {
            mRecyclerView.setItemAnimator(animator);
        }
    
        public void addItemDecoration(RecyclerView.ItemDecoration decor) {
            mRecyclerView.addItemDecoration(decor);
        }
    
        public void addItemDecoration(RecyclerView.ItemDecoration decor, int index) {
            mRecyclerView.addItemDecoration(decor, index);
        }
    
        public void setViewPadding(int left, int top, int right, int bottom) {
            mRecyclerView.setPadding(left, top, right, bottom);
        }
    
    }

    PullRefreshView.java

    /**
     * 类说明: 自定义的上下拉刷新控件
     * Author: gaobaiq
     * Date: 2016/5/9 17:27
     */
    public class PullRefreshView extends ViewGroup {
    
        private static final String TAG = PullRefreshView.class.getSimpleName();
    
        protected Context mContext;
    
        //头部下拉的最小高度
        private static final int HEAD_DEFAULT_HEIGHT = 100;
    
        //尾部上拉的最小高度
        private static final int TAIL_DEFAULT_HEIGHT = 100;
    
        /**
         * 头部容器
         */
        private LinearLayout mHeadLayout;
    
        /**
         * 头部View
         */
        private View mHead;
    
        /**
         * 头部的高度
         */
        private int mHeadHeight = HEAD_DEFAULT_HEIGHT;
    
    
        /**
         * 尾部容器
         */
        private LinearLayout mTailLayout;
    
        /**
         * 尾部View
         */
        private View mTail;
    
        /**
         * 尾部的高度
         */
        private int mTailHeight = TAIL_DEFAULT_HEIGHT;
    
    
        /**
         * 滑动的偏移量
         */
        private int mScrollOffset = 0;
    
        /**
         * 标记 无状态(既不是上拉 也 不是下拉)
         */
        private final int STATE_NOT = -1;
    
        /**
         * 标记 上拉状态
         */
        private final int STATE_UP = 1;
    
        /**
         * 标记 下拉状态
         */
        private final int STATE_DOWN = 2;
    
        /**
         * 当前状态
         */
        private int mCurrentState = STATE_NOT;
    
        /**
         * 是否处于下拉 正在更新状态
         */
        private boolean mIsPullDown = false;
    
        /**
         * 是否处于上拉 正在加载状态
         */
        private boolean mIsPullUp = false;
    
        /**
         * 是否启用下拉功能(默认不开启)
         */
        private boolean mIsDownRefresh = true;
    
        /**
         * 是否启用上拉功能(默认不开启)
         */
        private boolean mIsUpRefresh = false;
    
        /**
         * 加载状态
         */
        private boolean mIsLoading = false;
    
        private int mDamp = 4;
    
        /**
         * 头部状态监听器
         */
        private OnHeadStateListener mHeadStateListener;
    
        /**
         * 尾部状态监听器
         */
        private OnTailStateListener mTailStateListener;
    
        /**
         * 上拉监听器
         */
        private OnPullUpRefreshListener mPullUpRefreshListener;
    
        /**
         * 下拉监听器
         */
        private OnPullDownRefreshListener mPullDownRefreshListener;
    
        /**
         * 是否还有更多数据。
         */
        private boolean isMore = true;
    
        public PullRefreshView(Context context) {
            this(context, null);
        }
    
        public PullRefreshView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public PullRefreshView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            setClipToPadding(false);
            initHeadLayout();
            initTailLayout();
        }
    
        /**
         * 初始化头部
         */
        private void initHeadLayout() {
            mHeadLayout = new LinearLayout(mContext);
            LayoutParams lp = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            mHeadLayout.setGravity(Gravity.CENTER | Gravity.BOTTOM);
            mHeadLayout.setLayoutParams(lp);
            addView(mHeadLayout);
        }
    
        /**
         * 设置头部View
         *
         * @param head
         */
        public void setHead(View head) {
            mHead = head;
            mHeadLayout.removeAllViews();
            mHeadLayout.addView(mHead);
    
            //获取头部高度
            mHeadLayout.post(new Runnable() {
                @Override
                public void run() {
                    if (mHead.getHeight() > HEAD_DEFAULT_HEIGHT) {
                        mHeadHeight = mHead.getHeight();
                    } else {
                        mHeadHeight = HEAD_DEFAULT_HEIGHT;
                    }
                    Log.e(TAG, "mHeadHeight" + mHeadHeight);
                    //当获取到头部高度的时候,如果正处于下拉刷新状态,应该把头部打开。
                    if (mIsPullDown) {
                        scroll(-mHeadHeight);
                    }
                    invalidate();
                }
            });
        }
    
        /**
         * 初始化尾部
         */
        private void initTailLayout() {
            mTailLayout = new LinearLayout(mContext);
            LayoutParams lp = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            mTailLayout.setGravity(Gravity.CENTER | Gravity.BOTTOM);
            mTailLayout.setLayoutParams(lp);
            addView(mTailLayout);
        }
    
        /**
         * 设置尾部View
         *
         * @param tail
         */
        public void setTail(View tail) {
            mTail = tail;
            mTailLayout.removeAllViews();
            mTailLayout.addView(mTail);
    
            //获取尾部高度
            mTailLayout.post(new Runnable() {
                @Override
                public void run() {
                    if (mTail.getHeight() > TAIL_DEFAULT_HEIGHT) {
                        mTailHeight = mTail.getHeight();
                    } else {
                        mTailHeight = TAIL_DEFAULT_HEIGHT;
                    }
                    Log.e(TAG, "mTailHeight" + mTailHeight);
                    //当获取到尾部高度的时候,如果正处于上拉刷新状态,应该把尾部打开。
                    if (mIsPullUp) {
                        scroll(mTailHeight);
                    }
                }
            });
            invalidate();
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
    
            //布局头部
            View head = getChildAt(0);
            head.layout(getPaddingLeft(), -mHeadHeight, getPaddingLeft() + head.getMeasuredWidth(), 0);
    
            //布局尾部
            View tail = getChildAt(1);
            tail.layout(getPaddingLeft(), getMeasuredHeight(), getPaddingLeft() + tail.getMeasuredWidth(), getMeasuredHeight() + mTailHeight);
    
            //布局内容容器
            int count = getChildCount();
            if (count > 2) {
                View content = getChildAt(2);
                content.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + content.getMeasuredWidth(), getPaddingTop() + content.getMeasuredHeight());
            }
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            //测量头部高度
            View head = getChildAt(0);
            measureChild(head, widthMeasureSpec, heightMeasureSpec);
    
            //测量尾部高度
            View tail = getChildAt(1);
            measureChild(tail, widthMeasureSpec, heightMeasureSpec);
    
            //测量内容容器宽高
            int count = getChildCount();
            int contentHeight = 0;
            int contentWidth = 0;
            if (count > 2) {
                View content = getChildAt(2);
                measureChild(content, widthMeasureSpec, heightMeasureSpec);
                contentHeight = content.getMeasuredHeight();
                contentWidth = content.getMeasuredWidth();
            }
    
            //设置PullRefresView的宽高
            setMeasuredDimension(measureWidth(widthMeasureSpec, contentWidth), measureHeigth(heightMeasureSpec, contentHeight));
        }
    
        private int measureWidth(int measureSpec, int contentWidth) {
            int result = 0;
            int specMode = MeasureSpec.getMode(measureSpec);
            int specSize = MeasureSpec.getSize(measureSpec);
    
            if (specMode == MeasureSpec.EXACTLY) {
                result = specSize;
            } else {
                result = contentWidth + getPaddingLeft() + getPaddingRight();
                if (specMode == MeasureSpec.AT_MOST) {
                    result = Math.min(result, specSize);
                }
            }
    
            return result;
        }
    
        private int measureHeigth(int measureSpec, int contentHeight) {
            int result = 0;
            int specMode = MeasureSpec.getMode(measureSpec);
            int specSize = MeasureSpec.getSize(measureSpec);
    
            if (specMode == MeasureSpec.EXACTLY) {
                result = specSize;
            } else {
                result = contentHeight + getPaddingTop() + getPaddingBottom();
                if (specMode == MeasureSpec.AT_MOST) {
                    result = Math.min(result, specSize);
                }
            }
    
            return result;
        }
    
        /**
         * 设置是否启用上下拉功能
         *
         * @param isDownRefresh 是否开启下拉功能 默认开启
         * @param isUpRefresh   是否开启上拉功能 默认不开启
         */
        public void setRefresh(boolean isDownRefresh, boolean isUpRefresh) {
            mIsDownRefresh = isDownRefresh;
            mIsUpRefresh = isUpRefresh;
        }
    
        /**
         * 还原
         */
        private void restore() {
            mCurrentState = STATE_NOT;
            scroll(0);
        }
    
        /**
         * 通知刷新完成
         */
        public void refreshFinish() {
            restore();
            if (mIsLoading) {
                mIsLoading = false;
                if (mIsPullUp) {
                    mIsPullUp = false;
                    if (mTailStateListener != null && isMore) {
                        mTailStateListener.onRetractTail(mTail);
                    }
                } else if (mIsPullDown) {
                    mIsPullDown = false;
                    if (mHeadStateListener != null) {
                        mHeadStateListener.onRetractHead(mHead);
                    }
                }
            }
        }
    
        public void isMore(boolean isMore) {
            this.isMore = isMore;
            if (mTailStateListener != null) {
                if (isMore) {
                    mTailStateListener.onHasMore(mTail);
                } else {
                    mTailStateListener.onNotMore(mTail);
                }
            }
        }
    
        /**
         * 触发下拉刷新
         */
        public void triggerPullDownRefresh() {
    
            if (!mIsDownRefresh) {
                return;
            }
    
            if (!mIsLoading) {
                mIsLoading = true;
                mIsPullDown = true;
                mCurrentState = STATE_NOT;
                scroll(-mHeadHeight);
                if (mHeadStateListener != null) {
                    mHeadStateListener.onRefreshHead(mHead);
                }
    
                if (mPullDownRefreshListener != null) {
                    mPullDownRefreshListener.onRefresh();
                }
            }
        }
    
        /**
         * 触发上拉刷新
         */
        public void triggerPullUpRefresh() {
    
            if (!mIsUpRefresh) {
                return;
            }
    
            if (!mIsLoading) {
                mIsLoading = true;
                mIsPullUp = true;
                mCurrentState = STATE_NOT;
                scroll(mTailHeight);
                if (mTailStateListener != null && isMore) {
                    mTailStateListener.onRefreshTail(mTail);
                }
    
                if (isMore) {
                    if (mPullUpRefreshListener != null) {
                        mPullUpRefreshListener.onRefresh();
                    }
                } else {
                    refreshFinish();
                }
    
            }
        }
    
        /**
         * @param offset
         */
        private void scroll(int offset) {
    
            if (offset < 0 && !mIsDownRefresh) {
                return;
            }
    
            if (offset > 0 && !mIsUpRefresh) {
                return;
            }
    
            scrollTo(0, offset);
            mScrollOffset = Math.abs(offset);
    
            if (mCurrentState == STATE_DOWN && mHeadStateListener != null) {
                mHeadStateListener.onScrollChange(mHead, mScrollOffset, mScrollOffset >= mHeadHeight ? 100 : mScrollOffset * 100 / mHeadHeight);
            }
    
            if (mCurrentState == STATE_UP && mTailStateListener != null && isMore) {
                mTailStateListener.onScrollChange(mTail, mScrollOffset, mScrollOffset >= mTailHeight ? 100 : mScrollOffset * 100 / mTailHeight);
            }
        }
    
        /**
         * 设置拉动阻力 (1到10)
         *
         * @param damp
         */
        public void setDamp(int damp) {
            if (damp < 1) {
                mDamp = 1;
            } else if (damp > 10) {
                mDamp = 10;
            } else {
                mDamp = damp;
            }
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            int y = (int) event.getY();
    
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    return true;
                case MotionEvent.ACTION_MOVE:
                    if (mY > y) {
                        if (mCurrentState == STATE_UP) {
                            scroll((mY - y) / mDamp);
                        }
                    } else if (mCurrentState == STATE_DOWN) {
                        scroll((mY - y) / mDamp);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (!mIsPullDown && !mIsPullUp) {
                        if (mCurrentState == STATE_DOWN) {
                            if (mScrollOffset < mHeadHeight) {
                                restore();
                            } else {
                                triggerPullDownRefresh();
                            }
                        } else if (mCurrentState == STATE_UP) {
                            if (mScrollOffset < mTailHeight) {
                                restore();
                            } else {
                                triggerPullUpRefresh();
                            }
                        } else {
                            restore();
                        }
                    }
                    mY = 0;
    
                    break;
                default:
    
                    break;
            }
            return super.onTouchEvent(event);
        }
    
        int mY = 0;
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
    
            int y = (int) ev.getY();
    
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mY = (int) ev.getY();
                    return false;
                case MotionEvent.ACTION_MOVE:
                    if (mIsLoading) {
                        return false;
                    }
    
                    if (pullDown() && y - mY > 20) {
                        mCurrentState = STATE_DOWN;
                        return true;
                    }
    
                    if (pullUp() && mY - y > 20) {
                        mCurrentState = STATE_UP;
                        return true;
                    }
    
                    return false;
                case MotionEvent.ACTION_UP:
    
                    return false;
            }
    
            return false;
        }
    
        protected boolean pullDown() {
            return mCurrentState != STATE_UP && mIsDownRefresh && isTop();
        }
    
        protected boolean pullUp() {
            return mCurrentState != STATE_DOWN && mIsUpRefresh && isBottom();
        }
    
        protected boolean isTop() {
    
            if (getChildCount() < 2) {
                return true;
            }
    
            View view = getChildAt(2);
    
            if (view instanceof ViewGroup) {
    
                if (view instanceof ScrollView) {
                    ScrollView scrollView = (ScrollView) view;
                    return scrollView.getScrollY() <= 0;
                } else {
                    return isChildTop((ViewGroup) view);
                }
            } else {
                return true;
            }
        }
    
    
        protected boolean isChildTop(ViewGroup viewGroup) {
            int minY = 0;
            int count = viewGroup.getChildCount();
            for (int i = 0; i < count; i++) {
                View view = viewGroup.getChildAt(i);
                int topMargin = 0;
                LayoutParams lp = view.getLayoutParams();
                if (lp instanceof MarginLayoutParams) {
                    topMargin = ((MarginLayoutParams) lp).topMargin;
                }
                int top = view.getTop() - topMargin;
                minY = Math.min(minY, top);
            }
            return minY >= 0;
        }
    
        protected boolean isBottom() {
    
            if (getChildCount() < 2) {
                return false;
            }
    
            View view = getChildAt(2);
    
            if (view instanceof ViewGroup) {
                if (view instanceof ScrollView) {
                    ScrollView scrollView = (ScrollView) view;
                    if (scrollView.getChildCount() > 0) {
                        return scrollView.getScrollY() >= scrollView.getChildAt(0).getHeight() - scrollView.getHeight();
                    } else {
                        return true;
                    }
                } else {
                    return isChildBottom((ViewGroup) view);
                }
            } else {
                return true;
            }
        }
    
    
        protected boolean isChildBottom(ViewGroup viewGroup) {
            int maxY = 0;
            int count = viewGroup.getChildCount();
    
            if (count == 0) {
                return false;
            }
    
            for (int i = 0; i < count; i++) {
                View view = viewGroup.getChildAt(i);
                int bottomMargin = 0;
                LayoutParams lp = view.getLayoutParams();
                if (lp instanceof MarginLayoutParams) {
                    bottomMargin = ((MarginLayoutParams) lp).bottomMargin;
                }
                int bottom = view.getBottom() + bottomMargin;
                maxY = Math.max(maxY, bottom);
            }
    
            int h = viewGroup.getMeasuredHeight() - viewGroup.getPaddingBottom();
    
            return maxY <= h;
        }
    
        /**
         * 设置头部监听器
         *
         * @param listener
         */
        public void setOnHeadStateListener(OnHeadStateListener listener) {
            mHeadStateListener = listener;
        }
    
        /**
         * 设置尾部监听器
         *
         * @param listener
         */
        public void setOnTailStateListener(OnTailStateListener listener) {
            mTailStateListener = listener;
        }
    
        /**
         * 设置上拉监听器
         *
         * @param listener
         */
        public void setOnPullUpRefreshListener(OnPullUpRefreshListener listener) {
            mPullUpRefreshListener = listener;
        }
    
        /**
         * 设置下拉监听器
         *
         * @param listener
         */
        public void setOnPullDownRefreshListener(OnPullDownRefreshListener listener) {
            mPullDownRefreshListener = listener;
        }
    
    
        /**
         * 移除头部监听器
         */
        public void removeOnHeadStateListener() {
            mHeadStateListener = null;
        }
    
        /**
         * 移除尾部监听器
         */
        public void removeOnTailStateListener() {
            mTailStateListener = null;
        }
    
        /**
         * 移除上拉监听器
         */
        public void removeOnPullUpRefreshListener() {
            mPullUpRefreshListener = null;
        }
    
        /**
         * 移除下拉监听器
         */
        public void removeOnPullDownRefreshListener() {
            mPullDownRefreshListener = null;
        }
    
    
        //----------------  监听接口  -------------------//
    
        /**
         * 头部状态监听器
         */
        public interface OnHeadStateListener {
    
            /**
             * 头部滑动变化
             *
             * @param head         头部View
             * @param scrollOffset 滑动距离
             * @param scrollRatio  从开始到触发阀值的滑动比率(0到100)如果滑动到达了阀值,就算在滑动,这个值也是100
             */
            void onScrollChange(View head, int scrollOffset, int scrollRatio);
    
            /**
             * 头部处于刷新状态 (触发下拉刷新的时候调用)
             *
             * @param head 头部View
             */
            void onRefreshHead(View head);
    
            /**
             * 头部收起
             *
             * @param head 头部View
             */
            void onRetractHead(View head);
    
        }
    
        /**
         * 头部状态监听器
         */
        public interface OnTailStateListener {
    
            /**
             * 尾部滑动变化
             *
             * @param tail         尾部View
             * @param scrollOffset 滑动距离
             * @param scrollRatio  从开始到触发阀值的滑动比率(0到100)如果滑动到达了阀值,就算在滑动,这个值也是100
             */
            void onScrollChange(View tail, int scrollOffset, int scrollRatio);
    
            /**
             * 尾部处于加载状态 (触发上拉加载的时候调用)
             *
             * @param tail 尾部View
             */
            void onRefreshTail(View tail);
    
            /**
             * 尾部收起
             *
             * @param tail 尾部View
             */
            void onRetractTail(View tail);
    
            /**
             * 没有更多
             *
             * @param tail
             */
            void onNotMore(View tail);
    
            /**
             * 有更多
             *
             * @param tail
             */
            void onHasMore(View tail);
        }
    
    
        /**
         * 上拉加载监听器
         */
        public interface OnPullUpRefreshListener {
            void onRefresh();
        }
    
        /**
         * 下拉更新监听器
         */
        public interface OnPullDownRefreshListener {
            void onRefresh();
        }
    }

    HeadView.java

    /**
     * 类说明: 下拉刷新头部View
     * Author: gaobaiq
     * Date: 2016/5/9 19:07
     */
    public class HeadView extends LinearLayout implements PullRefreshView.OnHeadStateListener {
    
        ImageView ivHeaderDownArrow;
        ImageView ivHeaderLoading;
        TextView textView;
    
        AnimationDrawable animationDrawable;
    
        private boolean isReach = false;
    
        public HeadView(Context context) {
            super(context);
            animationDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.progress_round);
            init(context);
        }
    
        private void init(Context context) {
            LayoutInflater inflater = LayoutInflater.from(context);
            View layout = inflater.inflate(R.layout.head_view_layout, this, false);
            this.addView(layout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            initView(layout);
            restore();
            this.setPadding(0, 30, 0, 20);
        }
    
        private void initView(View view){
            ivHeaderDownArrow = (ImageView)view.findViewById(R.id.iv_header_down_arrow);
            ivHeaderLoading = (ImageView)view.findViewById(R.id.iv_header_loading);
            textView = (TextView)view.findViewById(R.id.tv_header_state);
        }
    
        @Override
        public void onScrollChange(View head, int scrollOffset, int scrollRatio) {
    
            if (scrollRatio == 100 && !isReach) {
                textView.setText("松开刷新");
                ivHeaderDownArrow.setRotation(180);
                isReach = true;
            } else if (scrollRatio != 100 && isReach) {
                textView.setText("下拉刷新");
                ivHeaderDownArrow.setRotation(0);
                isReach = false;
            }
        }
    
        @Override
        public void onRefreshHead(View head) {
            ivHeaderLoading.setVisibility(VISIBLE);
            ivHeaderDownArrow.setVisibility(GONE);
            ivHeaderLoading.setImageDrawable(animationDrawable);
            animationDrawable.start();
            textView.setText("正在刷新");
        }
    
        @Override
        public void onRetractHead(View head) {
            restore();
            animationDrawable.stop();
            isReach = false;
        }
    
        private void restore() {
            ivHeaderLoading.setVisibility(GONE);
            ivHeaderDownArrow.setVisibility(VISIBLE);
            ivHeaderLoading.setImageResource(R.drawable.loading1);
            ivHeaderDownArrow.setImageResource(R.drawable.icon_down_arrow);
            ivHeaderDownArrow.setRotation(0);
            textView.setText("下拉刷新");
        }
    }

    TailView.java

    /**
     * 类说明: 尾部上拉加载更多
     * Author: gaobaiq
     * Date: 2016/4/18 10:12
     */
    public class TailView extends LinearLayout implements PullRefreshView.OnTailStateListener {
    
        ImageView ivHeaderDownArrow;
        ImageView ivHeaderLoading;
        TextView textView;
    
        AnimationDrawable animationDrawable;
    
        private boolean isReach = false;
        private boolean isMore = true;
    
        public TailView(Context context) {
            super(context);
            animationDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.progress_round);
            init(context);
        }
    
        private void init(Context context) {
            LayoutInflater inflater = LayoutInflater.from(context);
            View layout = inflater.inflate(R.layout.head_view_layout, this, false);
            this.addView(layout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            initView(layout);
            restore();
            this.setPadding(0, 20, 0, 30);
        }
    
        private void initView(View view){
            ivHeaderDownArrow = (ImageView)view.findViewById(R.id.iv_header_down_arrow);
            ivHeaderLoading = (ImageView)view.findViewById(R.id.iv_header_loading);
            textView = (TextView)view.findViewById(R.id.tv_header_state);
        }
    
        @Override
        public void onScrollChange(View tail, int scrollOffset, int scrollRatio) {
            if (isMore) {
                if (scrollRatio == 100 && !isReach) {
                    textView.setText("松开加载");
                    ivHeaderDownArrow.setRotation(0);
                    isReach = true;
                } else if (scrollRatio != 100 && isReach) {
                    textView.setText("上拉加载");
                    isReach = false;
                    ivHeaderDownArrow.setRotation(180);
                }
            }
        }
    
        @Override
        public void onRefreshTail(View tail) {
            if (isMore) {
                ivHeaderLoading.setVisibility(VISIBLE);
                ivHeaderDownArrow.setVisibility(GONE);
                ivHeaderLoading.setImageDrawable(animationDrawable);
    //            AnimationDrawable animationDrawable = (AnimationDrawable) head.getBackground();
                animationDrawable.start();
                textView.setText("正在加载");
            }
        }
    
        @Override
        public void onRetractTail(View tail) {
    //            animationDrawable = (AnimationDrawable) head.getBackground();
            if (isMore) {
                restore();
                animationDrawable.stop();
                isReach = false;
            }
        }
    
        @Override
        public void onNotMore(View tail) {
            ivHeaderLoading.setVisibility(GONE);
            ivHeaderDownArrow.setVisibility(GONE);
            textView.setText("已经全部加载完毕");
            isMore = false;
        }
    
        @Override
        public void onHasMore(View tail) {
            ivHeaderLoading.setVisibility(GONE);
            ivHeaderDownArrow.setVisibility(VISIBLE);
            textView.setText("上拉加载");
            isMore = true;
        }
    
        private void restore() {
            ivHeaderLoading.setVisibility(GONE);
            ivHeaderDownArrow.setVisibility(VISIBLE);
            ivHeaderLoading.setImageResource(R.drawable.loading1);
            ivHeaderDownArrow.setImageResource(R.drawable.icon_down_arrow);
            ivHeaderDownArrow.setRotation(180);
            textView.setText("上拉加载");
        }
    }

    PullRefreshUtil.java

    /**
     * 类说明:
     * Author: gaobaiq
     * Date: 2016/5/9 20:04
     */
    public class PullRefreshUtil {
    
        /**
         * 刷新控件的基本配件 (头部、尾部都用默认的)
         *
         * @param view          刷新控件
         * @param isDownRefresh 是否开启下拉刷新
         * @param isUpRefresh   是否开启上拉加载
         */
        public static void setRefresh(PullRefreshView view, boolean isDownRefresh, boolean isUpRefresh) {
    
            HeadView headView = null;
            TailView tailView = null;
            if (isDownRefresh) {
                headView = new HeadView(view.getContext());
            }
    
            if (isUpRefresh) {
                tailView = new TailView(view.getContext());
            }
    
            setRefresh(view, isDownRefresh, isUpRefresh, headView, tailView, headView, tailView);
        }
    
        /**
         * 刷新控件的基本配件 (自定义头部、尾部用默认的)
         *
         * @param view              刷新控件
         * @param isDownRefresh     是否开启下拉刷新
         * @param isUpRefresh       是否开启上拉加载
         * @param headView          头部View
         * @param headStateListener 头部监听器
         */
        public static void setRefresh(PullRefreshView view, boolean isDownRefresh, boolean isUpRefresh, View headView, PullRefreshView.OnHeadStateListener headStateListener) {
    
            TailView tailView = null;
            if (isUpRefresh) {
                tailView = new TailView(view.getContext());
            }
            setRefresh(view, isDownRefresh, isUpRefresh, headView, tailView, headStateListener, tailView);
        }
    
        /**
         * 刷新控件的基本配件 (自定义尾部 、头部用默认的)
         *
         * @param view              刷新控件
         * @param isDownRefresh     是否开启下拉刷新
         * @param isUpRefresh       是否开启上拉加载
         * @param tailView          尾部View
         * @param tailStateListener 尾部监听器
         */
        public static void setRefresh(PullRefreshView view, boolean isDownRefresh, boolean isUpRefresh, View tailView, PullRefreshView.OnTailStateListener tailStateListener) {
    
            HeadView headView = null;
            if (isDownRefresh) {
                headView = new HeadView(view.getContext());
            }
            setRefresh(view, isDownRefresh, isUpRefresh, headView, tailView, headView, tailStateListener);
        }
    
        /**
         * 刷新控件的基本配件 (自定义头部、尾部)
         *
         * @param view              刷新控件
         * @param isDownRefresh     是否开启下拉刷新
         * @param isUpRefresh       是否开启上拉加载
         * @param headView          头部View
         * @param tailView          尾部View
         * @param headStateListener 头部监听器
         * @param tailStateListener 尾部监听器
         */
        public static void setRefresh(PullRefreshView view, boolean isDownRefresh, boolean isUpRefresh, View headView, View tailView, PullRefreshView.OnHeadStateListener headStateListener, PullRefreshView.OnTailStateListener tailStateListener) {
    
            view.setRefresh(isDownRefresh, isUpRefresh);
    
            if (isDownRefresh) {
                view.setHead(headView);
                view.setOnHeadStateListener(headStateListener);
            }
    
            if (isUpRefresh) {
                view.setTail(tailView);
                view.setOnTailStateListener(tailStateListener);
            }
        }
    }

    progress_round.xml

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="false">
        <item
            android:drawable="@drawable/loading1"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading2"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading3"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading4"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading5"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading6"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading7"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading8"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading9"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading10"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading11"
            android:duration="50" />
        <item
            android:drawable="@drawable/loading12"
            android:duration="50" />
    </animation-list>

    head_view_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="5dp"
        android:gravity="center">
    
        <ImageView
            android:id="@+id/iv_header_down_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/icon_down_arrow" />
    
    
        <ImageView
            android:id="@+id/iv_header_loading"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:src="@drawable/progress_round"/>
    
        <TextView
            android:id="@+id/tv_header_state"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:paddingLeft="5dp"
            android:textSize="13sp"
            android:textColor="#979797"
            android:text="Loading" />
    
    </LinearLayout>
    

       调用:

    <com.app.gaobaiq.pullrefresh.PullRefreshRecyclerView
                    android:id="@+id/list"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"/>
    
    
    
    PullRefreshUtil.setRefresh(mList, true, true);
    mList.setOnPullDownRefreshListener(new PullRefreshView.OnPullDownRefreshListener() {
          @Override public void onRefresh() {
    mList.isMore(true); pageNum = 1; loadData(); } }); 
    mList.setOnPullUpRefreshListener( new PullRefreshView.OnPullUpRefreshListener() { @Override public void onRefresh() { pageNum++; loadData(); } }); 
    
    // 加载完成 if (mList!= null) { mList.refreshFinish(); }
    <com.app.gaobaiq.pullrefresh.PullRefreshView
                android:id="@+id/refresh_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
     
     
                <ScrollView
                    android:id="@+id/scrollView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
     
     
                    <LinearLayout android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="vertical">
     
                             
     
                        </LinearLayout>
     
                </ScrollView>
     
            </com.app.gaobaiq.pullrefresh.PullRefreshView>
     
     
     
    PullRefreshUtil.setRefresh(mRefreshView, true, true);
            mRefreshView.setOnPullDownRefreshListener(
                    new PullRefreshView.OnPullDownRefreshListener() {
                        @Override public void onRefresh() {
                            pageNum = 1;
                            mRefreshView.isMore(true);
                            loadData();
                        }
                    });
            mRefreshView.setOnPullUpRefreshListener(
                    new PullRefreshView.OnPullUpRefreshListener() {
                        @Override public void onRefresh() {
                            pageNum++;
                            loadData();
                        }
                    });
     
     
    // 加载完成
    if (mRefreshView != null) {
                mRefreshView.refreshFinish();
            }
  • 相关阅读:
    段落排版--对齐
    1055. The World's Richest (25)
    1054. The Dominant Color (20)
    (八十一)利用系统自带App来实现导航
    (八十)MapKit放置系统默认大头针和自定义大头针
    (七十九)MapKit的基本使用
    1052. Linked List Sorting (25)
    (七十八)使用第三方框架INTULocationManager实现定位
    (七十七)地理编码与反地理编码
    1051. Pop Sequence (25)
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/7425535.html
Copyright © 2011-2022 走看看