RecyclerView下拉刷新和载入很多其它

之前一直写的是ListVIew下拉刷新,可是好多朋友都说要RecycleView的下拉刷新和滑动载入。事实上,这个原理都是几乎相同。抽出时间,我就写了下RecycleView的下拉刷新和滑动载入很多其它。因此,这才写到博客里,记录一下。


在大家阅读这篇博客前。大家须要了解的知识

1.Scroller。实现弹性滑动的类,这个是经经常使用到的,不懂的请自觉先学习Scroller的知识。

2.事件分发机制。

事件是以ACTION_DOWN開始到ACTION_UP货ACTION_CANCEL结束的一个序列,期间事件分发,能够通过onInterceptTouchEvent方法和dispatchTouchEvent进行事件的阻止和消费。

3.RecyclerView的基本使用。

比方怎样加入一个Decoration.

4.onSizeChange的触发时机。onSizeChange()在View的layout中触发,它运行在全部控件的onMeasure()之后,因此能够直接获取到控件的測量长和宽。
       总体的思路:採用的是LinearLayout+RecyclerView的组合。在LinearLayout中加入HeaderView和FooterView。

当RecyclerView滑动到了最顶部,则能够触发下拉事件;当RecyclerView滑动到了底部,则能够触发滑动载入很多其它的事件。然后在通过事件分发。进行滑动事件的处理。

       先看一下效果:

   以下是自己定义View的代码,后面会逐一分析代码块:
package com.mjc.recyclerviewdemo.refresh;

import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
import android.widget.Scroller;

import com.mjc.recyclerviewdemo.CustomItemDecoration;

/**
 * Created by mjc on 2016/3/11.
 */
public class PullToRefreshRecycleView extends LinearLayout {

    //头部
    private IHeaderView mHeaderView;
    private int mHeaderHeight;

    //尾部
    private CustomFooterView mFooterView;
    private int mFooterHeight;

    //阻尼系数,越大,阻力越大
    public static final float RATIO = 0.5f;
    //当前是否阻止事件
    private boolean isIntercept;
    //是否正在刷新
    private boolean isRefreshing;
    //滑动类
    private Scroller mScroller;
    //刷新的View
    private RecyclerView mRefreshView;

    private Context mContext;

    private int mMaxScrollHeight;

    private boolean isFirst = true;

    public static final int NORMAL = 0;
    public static final int PULL_TO_REFRESH = 1;
    public static final int RELEASE_TO_REFRESH = 2;
    public static final int REFRESING = 3;
    private int mCurrentState;
    private int mTouchSlop;

    private OnRefreshListener listener;

    private boolean isPullDownMotion;
    private int lastVisible;

    public PullToRefreshRecycleView(Context context) {
        super(context);
        init(context);
    }

    public PullToRefreshRecycleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }


    private void init(Context context) {
        mContext = context;
        this.setOrientation(VERTICAL);
        mRefreshView = getRefreshView();
        mRefreshView.setBackgroundColor(Color.WHITE);
        LayoutParams listParams = new LayoutParams(-1, -1);
        mRefreshView.setLayoutParams(listParams);
        addView(mRefreshView);
        //加入HeaderView
        mHeaderView = new CustomHeaderView(context);
        LayoutParams params = new LayoutParams(-1, -2);
        mHeaderView.setLayoutParams(params);
        addView(mHeaderView, 0);
        //加入FooterView
        mFooterView = new CustomFooterView(context);
        LayoutParams fParams = new LayoutParams(-1, 200);
        mFooterView.setLayoutParams(fParams);
        addView(mFooterView, -1);
        //弹性滑动实现
        mScroller = new Scroller(context);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //第一次获取相关參数,并隐藏HeaderView,FooterView
        if (isFirst) {
            mHeaderHeight = mHeaderView.getMeasuredHeight();
            mMaxScrollHeight = mHeaderHeight * 3;
            resetHeaderLayout(-mHeaderHeight);

            mFooterHeight = mFooterView.getMeasuredHeight();
            resetFooterLayout(-mFooterHeight);
            Log.v("@mHeaderHeight", mHeaderHeight + "");
            Log.v("@mFooterHeight", mFooterHeight + "");
            isFirst = false;
        }
    }

    private void resetHeaderLayout(int offset) {
        LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
        params.topMargin = offset;
        mHeaderView.requestLayout();
    }

    private void resetFooterLayout(int offset) {
        LayoutParams params = (LayoutParams) mFooterView.getLayoutParams();
        params.bottomMargin = offset;
        mFooterView.requestLayout();
    }

    //按下时的位置,当事件被阻止时,第一次ActionDown事件,onTouchEvent无法获取这个位置
    //须要在onInterceptTouchEvent获取
    private float downY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //假设当前是正在刷新而且是下拉状态,则当前视图处理事件
        if (isRefreshing && mScrollY < 0) {
            return true;
        }
        //假设当前是刷新状态,而且处于上拉状态,则视图不可进入下拉状态
        if (mScrollY >= 0 && isRefreshing)
            return false;
        boolean isIntercept = false;
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                downY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:

                //假设达到了滑动条件
                if (Math.abs(ev.getY() - downY) >= mTouchSlop) {
                    if (ev.getY() - downY > 0) {//下拉
                        isIntercept = isEnablePullDown();
                        if (isIntercept)//设置下拉还是上滑的状态,true表示下拉动作
                            isPullDownMotion = true;

                    } else {//上滑
                        isIntercept = isEnableLoadMore();
                        if (isIntercept)//false表示上滑状态
                            isPullDownMotion = false;
                    }
                } else {
                    isIntercept = false;
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                //假设返回true,子视图假设包括点击事件。则无法进行处理
                isIntercept = false;
                break;
            case MotionEvent.ACTION_UP:
                isIntercept = false;
                break;
        }
        return isIntercept;
    }

    //记录当前滑动的位置
    private int mScrollY;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //第一次推断时,downY仅仅能从intercept中获取,之后从这里获取
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float dY = event.getY() - downY;
                if (isPullDownMotion)//下拉
                    doPullDownMoveEvent(dY);
                else {//自己主动载入很多其它
                    doLoadMoreEvent(dY);
                }
                break;
            case MotionEvent.ACTION_UP:

                if (isPullDownMotion) {
                    //处理下拉结果
                    doPullDownResult();
                } else {
                    //处理滑动载入很多其它结果
                    doLoadMoreResult();
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                //同ACTION_UP
                if (isPullDownMotion) {
                    doPullDownResult();
                } else {
                    doLoadMoreResult();

                }

                break;
        }
        return true;
    }

    /**
     * 处理载入很多其它
     */
    private void doLoadMoreResult() {
        //手指松开时,假设FooterView,没有全然滑动出来。自己主动滑动出来
        scrollTo(0, mFooterHeight);
        mScrollY = getScrollY();
        if (!isRefreshing) {
            isRefreshing = true;
            if (listener != null)
                listener.onLoadMore();
        }

    }

    /**
     * 载入很多其它完毕后调用
     */
    public void completeLoadMore() {
        scrollTo(0, 0);
        mScrollY = 0;
        isRefreshing = false;
        LinearLayoutManager manager = (LinearLayoutManager) mRefreshView.getLayoutManager();
        int count = manager.getItemCount();
        if (count > lastVisible + 1)//载入了很多其它数据
            mRefreshView.scrollToPosition(lastVisible + 1);
    }

    //处理载入很多其它
    private void doLoadMoreEvent(float y) {
        int scrollY = (int) (mScrollY - y);
        if (scrollY < 0) {
            scrollY = 0;
        }


        if (scrollY > mFooterHeight) {
            scrollY = mFooterHeight;
        }
        Log.v("@scrollY", scrollY + "");
        scrollTo(0, scrollY);
    }

    /**
     * 处理释放后的操作
     */
    private void doPullDownResult() {
        //先获取如今滑动到的位置
        mScrollY = getScrollY();
        switch (mCurrentState) {
            case PULL_TO_REFRESH:
                mCurrentState = NORMAL;
                mHeaderView.onNormal();
                smoothScrollTo(0);
                break;
            case RELEASE_TO_REFRESH:
                //松开时,假设是释放刷新。则開始进行刷新动作
                if (!isRefreshing) {
                    //滑动到指定位置
                    smoothScrollTo(-mHeaderHeight);

                    mHeaderView.onRefreshing();
                    isRefreshing = true;
                    if (listener != null) {
                        //运行刷新回调
                        listener.onPullDownRefresh();

                    }
                    //假设当前滑动位置太靠下,则滑动到指定刷新位置
                } else if (mScrollY < -mHeaderHeight) {
                    smoothScrollTo(-mHeaderHeight);
                }
                break;

        }
    }

    /**
     * 获取到数据后,调用
     */
    public void completeRefresh() {
        isRefreshing = false;
        mCurrentState = NORMAL;
        smoothScrollTo(0);
    }

    private void doPullDownMoveEvent(float y) {
        int scrollY = (int) (mScrollY - y * RATIO);
        if (scrollY > 0) {
            scrollY = 0;
        }
        if (scrollY < -mMaxScrollHeight) {
            scrollY = -mMaxScrollHeight;
        }
        scrollTo(0, scrollY);
        if (isRefreshing)
            return;
        //设置对应的状态
        if (scrollY == 0) {
            mCurrentState = NORMAL;
            mHeaderView.onNormal();
        } else if (scrollY <= 0 && scrollY > -mHeaderHeight) {
            mCurrentState = PULL_TO_REFRESH;
            mHeaderView.onPullToRefresh(Math.abs(scrollY));
        } else if (scrollY <= -mHeaderHeight && scrollY >= -mMaxScrollHeight) {
            mCurrentState = RELEASE_TO_REFRESH;
            mHeaderView.onReleaseToRefresh(Math.abs(scrollY));
        }
    }

    /**
     * 从当前位置滑动到指定位置
     * @param y 滑动到的位置
     */
    private void smoothScrollTo(int y) {
        int dY = y - mScrollY;
        mScroller.startScroll(0, mScrollY, 0, dY, 500);
        invalidate();

    }

    private RecyclerView getRefreshView() {
        mRefreshView = new RecyclerView(mContext);
        mRefreshView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
        mRefreshView.addItemDecoration(new CustomItemDecoration(mContext, CustomItemDecoration.VERTICAL_LIST));
        return mRefreshView;
    }

    public void setAdapter(RecyclerView.Adapter adapter) {
        mRefreshView.setAdapter(adapter);
    }

    /**
     * 推断列表是否在最顶端
     * @return
     */
    private boolean isEnablePullDown() {
        LinearLayoutManager manager = (LinearLayoutManager) mRefreshView.getLayoutManager();
        int firstVisible = manager.findFirstVisibleItemPosition();
        //当前还没有数据,能够进行下拉
        if(manager.getItemCount()==0)
            return true;
        return firstVisible == 0 && manager.getChildAt(0).getTop() == 0;
    }

    /**
     * 推断列表是否滑动到了最底部
     * @return
     */
    private boolean isEnableLoadMore() {
        LinearLayoutManager manager = (LinearLayoutManager) mRefreshView.getLayoutManager();
        lastVisible = manager.findLastVisibleItemPosition();
        int totalCount = manager.getItemCount();
        //假设没有数据,仅仅能下拉刷新
        if (totalCount == 0)
            return false;
        int bottom = manager.findViewByPosition(lastVisible).getBottom();
        int decorHeight = manager.getBottomDecorationHeight(mRefreshView.getChildAt(0));
        //最后一个child的底部位置在当前视图的上面
        return totalCount == lastVisible + 1 && bottom + decorHeight <= getMeasuredHeight();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(0, mScroller.getCurrY());
            mScrollY = mScroller.getCurrY();
            invalidate();
        }
    }

    /**
     * 设置Footer的内容
     */
    public void setFooterViewState(boolean hasMoreData){
        if(hasMoreData){
            mFooterView.onRefreshing();
        }else{
            mFooterView.onNoData();
        }
    }
    public interface OnRefreshListener {
        void onPullDownRefresh();

        void onLoadMore();
    }

    public void setOnRefreshListener(OnRefreshListener listener) {

        this.listener = listener;
    }
}


    接下来一步一步的进行分析。
    首先,我们在构造方法中。调用了init(Context)方法,例如以下:
  private void init(Context context) {
        mContext = context;
        this.setOrientation(VERTICAL);
        mRefreshView = getRefreshView();
        mRefreshView.setBackgroundColor(Color.WHITE);
        LayoutParams listParams = new LayoutParams(-1, -1);
        mRefreshView.setLayoutParams(listParams);
        addView(mRefreshView);
        //加入HeaderView
        mHeaderView = new CustomHeaderView(context);
        LayoutParams params = new LayoutParams(-1, -2);
        mHeaderView.setLayoutParams(params);
        addView(mHeaderView, 0);
        //加入FooterView
        mFooterView = new CustomFooterView(context);
        LayoutParams fParams = new LayoutParams(-1, 200);
        mFooterView.setLayoutParams(fParams);
        addView(mFooterView, -1);
        //弹性滑动实现
        mScroller = new Scroller(context);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }


方法中。我们构造了HeaderView。RecyclerView以及FooterView。HeaderView和FooterView是简单的自己定义View,RecyclerView是直接构造的。而且在init()方法中。构造了Scroller,用于后面的弹性滑动须要。

接着,后面会运行onSizeChange方法:
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //第一次获取相关參数,并隐藏HeaderView。FooterView
        if (isFirst) {
            mHeaderHeight = mHeaderView.getMeasuredHeight();
            mMaxScrollHeight = mHeaderHeight * 3;
            resetHeaderLayout(-mHeaderHeight);

            mFooterHeight = mFooterView.getMeasuredHeight();
            resetFooterLayout(-mFooterHeight);
            Log.v("@mHeaderHeight", mHeaderHeight + "");
            Log.v("@mFooterHeight", mFooterHeight + "");
            isFirst = false;
        }
    }
设置了一个isFirst变量。防止反复设置里面的代码。

在这种方法里面,我们获取了HeaderView,FooterView的測量高。而且,我们设置了HeaderView。FooterView的margin值,隐藏了头部和尾部。


    再接着,就是与用户的交互过程,即用户的触摸事件。这个实现过程。分成两块,一块是下拉刷新,一块是滑动究竟部自己主动载入。这里我们一起分析。

 //按下时的位置,当事件被阻止时。第一次ActionDown事件,onTouchEvent无法获取这个位置
    //须要在onInterceptTouchEvent获取
    private float downY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //假设当前是正在刷新而且是下拉状态,则当前视图处理事件
        if (isRefreshing && mScrollY < 0) {
            return true;
        }
        //假设当前是刷新状态。而且处于上拉状态。则视图不可进入下拉状态
        if (mScrollY >= 0 && isRefreshing)
            return false;
        boolean isIntercept = false;
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                downY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:

                //假设达到了滑动条件
                if (Math.abs(ev.getY() - downY) >= mTouchSlop) {
                    if (ev.getY() - downY > 0) {//下拉
                        isIntercept = isEnablePullDown();
                        if (isIntercept)//设置下拉还是上滑的状态,true表示下拉动作
                            isPullDownMotion = true;

                    } else {//上滑
                        isIntercept = isEnableLoadMore();
                        if (isIntercept)//false表示上滑状态
                            isPullDownMotion = false;
                    }
                } else {
                    isIntercept = false;
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                //假设返回true,子视图假设包括点击事件,则无法进行处理
                isIntercept = false;
                break;
            case MotionEvent.ACTION_UP:
                isIntercept = false;
                break;
        }
        return isIntercept;
    }


onInterceptTouchEvent的作用,假设返回值为true,表示拦截事件。则事件交个当前控件进行处理,子View无法接收到事件;否则事件交给子View处理。  我们要知道,一般,一个事件序列,仅仅能由一个控件处理,也就是说。假设这个控件消费了ACTION_DOWN事件,那么,后面的ACTION_MOVE等都会交给他处理。可是。假设他的parentView在ACTION_MOVE中,拦截了事件,事件将会转交给ParentView的onTouchEvent处理。

 然后,開始分析代码,
  //假设当前是正在刷新而且是下拉状态,则当前视图处理事件
        if (isRefreshing && mScrollY < 0) {
            return true;
        }
        //假设当前是刷新状态,而且处于上拉状态。则视图不可进入下拉状态
        if (mScrollY >= 0 && isRefreshing)
            return false;

假设当前为下拉而且在刷新状态,则返回true,表示拦截事件,RecyclerView不可滑动。假设当前是滑动载入很多其它。而且刷新状态。则不拦截,由于后面我想在滑动载入很多其它时,RecyclerView能够滑动。  截止后面。在ACTION_DOWN事件中,我们记录下按下的y轴位置。然后是ACTION_MOVE;
     //假设达到了滑动条件
                if (Math.abs(ev.getY() - downY) >= mTouchSlop) {
                    if (ev.getY() - downY > 0) {//下拉
                        isIntercept = isEnablePullDown();
                        if (isIntercept)//设置下拉还是上滑的状态,true表示下拉动作
                            isPullDownMotion = true;

                    } else {//上滑
                        isIntercept = isEnableLoadMore();
                        if (isIntercept)//false表示上滑状态
                            isPullDownMotion = false;
                    }
                } else {
                    isIntercept = false;
                }


mTouchSlop是滑动的最小值。假设小于这个值,我们觉得没有滑动。大于这个值才算滑动。

假设当前滑动,大于这个值,继续走里面的if推断,假设当前是下拉状态,而且是能够下拉。那么拦截事件,否则进行滑动载入很多其它。假设满足滑动载入很多其它的条件,那么能够向上滑动。而且整个过程,用isPullDownMotion记录下了是向上还是向下的动作。后面在onTouchEvent中须要使用。最后,ACTION_UP和ACTION_CANCEL不拦截。假设拦截,会影响到子View的点击事件。


    最后是onTouchEvent
  //记录当前滑动的位置
    private int mScrollY;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //第一次推断时,downY仅仅能从intercept中获取。之后从这里获取
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float dY = event.getY() - downY;
                if (isPullDownMotion)//下拉
                    doPullDownMoveEvent(dY);
                else {//自己主动载入很多其它
                    doLoadMoreEvent(dY);
                }
                break;
            case MotionEvent.ACTION_UP:

                if (isPullDownMotion) {
                    //处理下拉结果
                    doPullDownResult();
                } else {
                    //处理滑动载入很多其它结果
                    doLoadMoreResult();
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                //同ACTION_UP
                if (isPullDownMotion) {
                    doPullDownResult();
                } else {
                    doLoadMoreResult();

                }

                break;
        }
        return true;
    }



看下拉环节(滑动载入很多其它相似,不再介绍),下拉过程ACTION_MOVE中先调用doPullDownMoveEvent,然后在ACTION_UP中调用了doPullDownResult。先看duPullDownMoveEvent
 private void doPullDownMoveEvent(float y) {
        int scrollY = (int) (mScrollY - y * RATIO);
        if (scrollY > 0) {
            scrollY = 0;
        }
        if (scrollY < -mMaxScrollHeight) {
            scrollY = -mMaxScrollHeight;
        }
        scrollTo(0, scrollY);
        if (isRefreshing)
            return;
        //设置对应的状态
        if (scrollY == 0) {
            mCurrentState = NORMAL;
            mHeaderView.onNormal();
        } else if (scrollY <= 0 && scrollY > -mHeaderHeight) {
            mCurrentState = PULL_TO_REFRESH;
            mHeaderView.onPullToRefresh(Math.abs(scrollY));
        } else if (scrollY <= -mHeaderHeight && scrollY >= -mMaxScrollHeight) {
            mCurrentState = RELEASE_TO_REFRESH;
            mHeaderView.onReleaseToRefresh(Math.abs(scrollY));
        }
    }


先计算滑动的位置,把滑动的位置限制在-mMaxScrollHeight和0之间,这样就不会滑动到其它地方。然后调用View的scrollTo方法,滑动到对应位置。

这样就完毕了触摸滑动。    后面。我们在通过滑动的位置,设置对应的状态。并回调HeaderView的各个状态的方法。


然后再看doPullDownResult
/**
     * 处理释放后的操作
     */
    private void doPullDownResult() {
        //先获取如今滑动到的位置
        mScrollY = getScrollY();
        switch (mCurrentState) {
            case PULL_TO_REFRESH:
                mCurrentState = NORMAL;
                mHeaderView.onNormal();
                smoothScrollTo(0);
                break;
            case RELEASE_TO_REFRESH:
                //松开时。假设是释放刷新,则開始进行刷新动作
                if (!isRefreshing) {
                    //滑动到指定位置
                    smoothScrollTo(-mHeaderHeight);

                    mHeaderView.onRefreshing();
                    isRefreshing = true;
                    if (listener != null) {
                        //运行刷新回调
                        listener.onPullDownRefresh();

                    }
                    //假设当前滑动位置太靠下,则滑动到指定刷新位置
                } else if (mScrollY < -mHeaderHeight) {
                    smoothScrollTo(-mHeaderHeight);
                }
                break;

        }
    }


这种方法,就是手指松开屏幕时触发。然后推断移动过程中的状态。假设是下拉刷新状态,则又一次恢复到下拉之前,调用smoothScrollTo(后面分析详细实现)。弹性滑动到初始位置。并设置状态为NORMAL状态。    假设松开时,是释放刷新状态。那么。先弹性滑动到刷新位置,并运行回调方法。


    如今分析。弹性滑动 smoothScrollTo
   /**
     * 从当前位置滑动到指定位置
     * @param y 滑动到的位置
     */
    private void smoothScrollTo(int y) {
        int dY = y - mScrollY;
        mScroller.startScroll(0, mScrollY, 0, dY, 500);
        invalidate();

    }



这种方法,必须要配合computeScroll使用。不然是没有效果的。详细的原因,须要查看View的绘制流程,这里我就不详细分析。

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(0, mScroller.getCurrY());
            mScrollY = mScroller.getCurrY();
            invalidate();
        }
    }



这个过程,是从Scroller的startScroll方法開始的,这种方法,调用后。Scroller的computeScrollOffset仅仅要动作没有运行完,就会一直返回true。调用了startScroll方法。须要调用invalide()来引起computeScroll方法的调用,而里面scrollTo方法。才是真正实现位移的原因。里面再调用invalidate又又一次引起了computeScroll方法,直到Scroller的computeOffset方法返回false。

   这样,每次都移动一小段位置,就实现了平滑滑动的效果。



用法。布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.mjc.recyclerviewdemo.refresh.PullToRefreshRecycleView
        android:id="@+id/prrv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>



Activity中
  mPRRV = (PullToRefreshRecycleView) findViewById(R.id.prrv);
        mPRRV.setOnRefreshListener(new PullToRefreshRecycleView.OnRefreshListener() {
            @Override
            public void onPullDownRefresh() {
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        datas.add(0, "add");
                        mAdapter.notifyDataSetChanged();
                        mPRRV.completeRefresh();
                    }
                }, 2000);

            }

            @Override
            public void onLoadMore() {
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        datas.add("李四");
                        datas.add("王五");
                        datas.add("张三");
                        datas.add("李四");
                        datas.add("王五");
                        datas.add("张三");

                        mAdapter.notifyDataSetChanged();
                        mPRRV.completeLoadMore();
                    }
                }, 1000);

            }
        });









附:源代码


posted @ 2018-02-04 10:04  zhchoutai  阅读(1274)  评论(0编辑  收藏  举报