1. 程式人生 > >Android RecyclerView下拉重新整理、上拉載入更多、到底自動載入更多

Android RecyclerView下拉重新整理、上拉載入更多、到底自動載入更多

一、廢話

搞了這麼久的Android,可能是我渠道比較閉塞,一直沒找到比較好用的下拉重新整理,往上找的第三方比較知名的一些,都說有這樣那樣的瑕疵,一直用的SwipeRefreshLayout 做下拉載入,然後在RecycleView最後多加一個item,只要載入了這個item,就自動載入更多,要多low有多low,完全沒有慾望去搞別人那種很炫酷的效果。

二、效果圖

附上原味效果圖(可以通過繼承本程式碼來定製,提供有相關方法和介面的,後續部落格會說明並舉例):


三、使用說明

1、5中狀態類別

程式碼區分了5中狀態供不同的應用場景使用,提供了方法可直接設定,也可以各種狀態無縫切換:

下拉重新整理兩種:可下拉、不可下拉(帶阻尼回彈)

上拉載入三種:上拉載入、到底自動載入、不載入(帶阻尼回彈)

2、匯入方法

原始碼只有兩個檔案,一個類(RefreshRelativeLayout)和一個佈局檔案(refresh_relative_layout.xml),所有程式碼均用的最原始的方式,並無其他比較高深的第三方的東西,可以直接匯入使用

3、呼叫方法

通過設定回撥介面監聽重新整理和載入時間,至於資料,可以通過getRecyclerView方法獲取RecyclerView,至於怎麼給RecyclerView加上資料操作,這裡我就不多廢話了,下面是一段呼叫程式碼:

//list是資料,adapter是介面卡,這兩個東西我就不放出來了,大家都懂
RefreshRelativeLayout recyclerView = (RefreshRelativeLayout) findViewById(R.id.recyclerView); recyclerView.setOnRefreshListener(new RefreshRelativeLayout.OnRefreshListener() { @Override publicvoidonRefresh(){ new Handler().postDelayed(new Runnable() { @Override
publicvoidrun(){ adapter.setData(list); recyclerView.setRefreshing(false); } }, 2000);//延遲兩秒操作 } }); recyclerView.setOnLoadListener(new RefreshRelativeLayout.OnLoadListener() { @Override publicvoidonLoad(){ new Handler().postDelayed(new Runnable() { @Override publicvoidrun(){ adapter.addData(list); recyclerView.setLoading(false); } }, 2000);//延遲兩秒操作 } }); adapter.setData(list); recyclerView.getRecyclerView().setAdapter(adapter); }

四、原始碼說明及原始碼

1、原始碼說明

整體構成是由一個父RelativeeLayout容器包裹三大部件(頭部RelativeLayout、RecyclerView、尾部RelativeLayout)構成;通過重寫父RelativeeLayout的dispatchTouchEvent方法監聽手指的觸控事件,然後再根據手指移動的位置做各種狀態的切換處理,細節可以看原始碼,註釋都非常清晰了的,至少我自以為是很清晰。

RecyclerView不用多說,頭部RelativeLayout和尾部RelativeLayout底下均包含了四個RelativeLayout用於表示四種不同的狀態,分別是:(1)下拉或上拉的時候未達到鬆開重新整理載入的狀態(2)鬆開重新整理或者載入(3)正在重新整理或者載入(4)刷子、載入完成,這個狀態可以設定延遲播放收起動畫的時間

重寫UI的方法(後續會寫個部落格介紹):

(1)、重寫一個refresh_relative_layout.xml,整體結構不能變,三大部件、4*2中狀態的RelativeLayout都不能動,但是可以改變裡面的內容,以達到不同的狀態顯示不同的UI的效果。

(2)。繼承RefreshRelativeLayout並重寫裡面的一些方法,具體那些方法重寫可以達到相關的功能,可以看原始碼,我通過分隔線進行了分類,另外提供了一個回撥介面,用於回調當前手指拖動的距離,這樣方便製作下拉或者上拉時候的某種拖動動效(例如朋友圈的彩色圓圈,拖動的時候就轉,按著不動的時候就不轉)。

2、原始碼(RefreshRelativeLayout)


import android.content.Context;
import android.graphics.Rect;
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.View;
import android.view.animation.Interpolator;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;

import com.imxiaoyu.common.R;

/**
 * 下拉重新整理以及上啦載入更多
 * Created by 她叫我小渝 on 2016/12/22.
 */

public classRefreshRelativeLayoutextendsRelativeLayout{

    /**
     * 常量
     */
    //pullDownType下拉型別的值;1-正常可以下拉重新整理  2-不可以下拉重新整理(有阻尼效果 )
    public static final int PULL_DOWN_TYPE_REFRESH = 1;
    public static final int PULL_DOWN_TYPE_NOT_PULL = 2;
    //pullUpType上拉型別的值;1-可以上拉載入 2-到了底部自動載入更多  3-不可以上拉重新整理(有阻尼效果)
    public static final int PULL_UP_TYPE_LOAD_PULL = 1;
    public static final int PULL_UP_TYPE_LOAD_AUTO = 2;
    public static final int PULL_UP_TYPE_NOT_PULL = 3;
    //pullDownState下拉狀態的值;1-下拉  2-鬆開重新整理  3-正在重新整理  4-重新整理完成
    public static final int PULL_DOWN_STATE_1 = 1;
    public static final int PULL_DOWN_STATE_2 = 2;
    public static final int PULL_DOWN_STATE_3 = 3;
    public static final int PULL_DOWN_STATE_4 = 4;
    //pullDownState上拉狀態的值;1-上拉  2-鬆開載入  3-正在載入  4-載入完成
    public static final int PULL_UP_STATE_1 = 1;
    public static final int PULL_UP_STATE_2 = 2;
    public static final int PULL_UP_STATE_3 = 3;
    public static final int PULL_UP_STATE_4 = 4;

    /**
     * UI
     */
    private RecyclerView recyclerView;
    private RelativeLayout rlyHead;
    private RelativeLayout rlyFoot;


    private RelativeLayout rlyHeadState1;
    private RelativeLayout rlyHeadState2;
    private RelativeLayout rlyHeadState3;
    private RelativeLayout rlyHeadState4;
    private RelativeLayout rlyFootState1;
    private RelativeLayout rlyFootState2;
    private RelativeLayout rlyFootState3;
    private RelativeLayout rlyFootState4;

    /**
     * 變數
     */
    private int pullDownType = PULL_DOWN_TYPE_REFRESH;//下拉型別;
    private int pullUpType = PULL_UP_TYPE_LOAD_PULL;//上拉型別;
    private int pullDownState = PULL_DOWN_STATE_1;//下拉狀態
    private int pullUpState = PULL_UP_STATE_1;//上拉狀態
    private boolean isRefreshing = false;//正在重新整理
    private boolean isLoading = false;//正在載入更多
    private int afterRefreshDelayTime = 200;//重新整理完成之後,延遲收起頭部檢視的時間
    private boolean isTouching = false;//是否正在按壓著螢幕

    // y方向上當前觸控點的前一次記錄位置
    private int previousY = 0;
    // y方向上的觸控點的起始記錄位置
    private int startY = 0;
    // y方向上的觸控點當前記錄位置
    private int currentY = 0;
    // y方向上兩次移動間移動的相對距離
    private int deltaY = 0;

    // 用於記錄childView的初始位置
    private Rect rectRlv = new Rect();//recyclerView的初始位置
    private Rect rectRlyHead = new Rect();//頭部的初始位置
    private Rect rectRlyFoot = new Rect();//尾部的初始位置

    //水平移動的距離
    private float moveHeight;

    /**
     * 介面
     */
    private OnRefreshListener onRefreshListener;//重新整理回撥
    private OnLoadListener onLoadListener;//載入回撥
    private OnTouchHeightListener onTouchHeightListener;//拖動的高度監聽,正數是下拉,負數是上啦(不會為0)


    publicRefreshRelativeLayout(Context context){
        this(context, null);
    }

    publicRefreshRelativeLayout(Context context, AttributeSet attrs){
        this(context, attrs, 0);
    }

    publicRefreshRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr){
        super(context, attrs, defStyleAttr);
        inflate(getContext(), getLayoutId(), this);
        initView();
    }


    privatevoidinitView(){
        recyclerView = (RecyclerView) findViewById(R.id.rlv);
        rlyHead = getHeadLayout((RelativeLayout) findViewById(R.id.rly_refresh_head));
        rlyFoot = getFootLayout((RelativeLayout) findViewById(R.id.rly_refresh_foot));

        rlyHeadState1 = getHeadState1Layout((RelativeLayout) findViewById(R.id.rly_head_state_1));
        rlyHeadState2 = getHeadState2Layout((RelativeLayout) findViewById(R.id.rly_head_state_2));
        rlyHeadState3 = getHeadState3Layout((RelativeLayout) findViewById(R.id.rly_head_state_3));
        rlyHeadState4 = getHeadState4Layout((RelativeLayout) findViewById(R.id.rly_head_state_4));

        rlyFootState1 = getFootState1Layout((RelativeLayout) findViewById(R.id.rly_foot_state_1));
        rlyFootState2 = getFootState2Layout((RelativeLayout) findViewById(R.id.rly_foot_state_2));
        rlyFootState3 = getFootState3Layout((RelativeLayout) findViewById(R.id.rly_foot_state_3));
        rlyFootState4 = getFootState4Layout((RelativeLayout) findViewById(R.id.rly_foot_state_4));

        //初始化一下三大件的位置
        initLayoutRect();
        recyclerView.setOnScrollChangeListener(new OnScrollChangeListener() {
            @Override
            publicvoidonScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY){
                //四個判定條件,1-不是正在載入 2-處於自動載入更多模式 3-列表已經到底部了 4-列表沒有在頂部(3-4一起的意思是列表到底部了,且列表的資料必須大於一頁)
                if (!isLoading && pullUpType == PULL_UP_TYPE_LOAD_AUTO && !recyclerView.canScrollVertically(1) && recyclerView.canScrollVertically(-1)) {
                    setPullUpState(PULL_UP_STATE_3);//到底部自動載入
                }
            }
        });
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));//recyclerView預設是ListView一樣的列表
    }

    //供外部呼叫的功能性方法↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓分隔線↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓


    /**
     * 返回RecyclerView,作為資料操作使用
     * @return
     */
    public RecyclerView getRecyclerView(){
        return recyclerView;
    }

    /**
     * 設定下拉型別 1-正常可以下拉重新整理(預設)  2-不可以下拉重新整理(有阻尼效果 )
     * ( 最好是在剛初始化的時候就呼叫)
     *
     * @param type
     */
    publicvoidsetPullDownType(int type){
        this.pullDownType = type;
        if (type == PULL_DOWN_TYPE_NOT_PULL) {
            rlyHead.setVisibility(GONE);
        } else {
            rlyHead.setVisibility(VISIBLE);
        }
        initLayoutRect();
    }

    /**
     * 設定上啦型別 1-可以下拉重新整理(預設) 2-到了底部自動載入更多  3-不可以上拉重新整理(有阻尼效果)
     * ( 最好是在剛初始化的時候就呼叫)
     *
     * @param type
     */
    publicvoidsetPullUpType(int type){
        this.pullUpType = type;
        if (type == PULL_UP_TYPE_NOT_PULL) {
            rlyFoot.setVisibility(GONE);
        } else {
            rlyFoot.setVisibility(VISIBLE);
        }
        initLayoutRect();
    }

    /**
     * 設定正在重新整理或者重新整理完成
     *
     * @param bln
     */
    publicvoidsetRefreshing(finalboolean bln){
        if (bln) {
            setPullDownState(PULL_DOWN_STATE_3);
        } else {
            setPullDownState(PULL_DOWN_STATE_4);
        }
    }

    /**
     * 設定正在重新整理或者重新整理完成
     *
     * @param bln
     */
    publicvoidsetLoading(finalboolean bln){
        if (bln) {
            setPullUpState(PULL_UP_STATE_3);
        } else {
            setPullUpState(PULL_UP_STATE_4);
        }
    }

    /**
     * 監聽下拉重新整理狀態
     *
     * @param listener
     */
    publicvoidsetOnRefreshListener(OnRefreshListener listener){
        this.onRefreshListener = listener;
    }

    /**
     * 監聽上啦或者自動載入狀態
     *
     * @param listener
     */
    publicvoidsetOnLoadListener(OnLoadListener listener){
        this.onLoadListener = listener;
    }

    /**
     * 拖動的高度監聽,正數是下拉,負數是上啦(不會為0,且只監聽拖動事件,按下和擡起均不回撥)
     *
     * @param listener true-正在載入  false-載入完成
     */
    publicvoidsetOnLoadListener(OnTouchHeightListener listener){
        this.onTouchHeightListener = listener;
    }

    /**
     * 設定重新整理完成之後收起檢視的時間,毫秒單位
     *
     * @param time
     */
    publicvoidsetAfterRefreshDelayTime(int time){
        this.afterRefreshDelayTime = time;
    }
    //供外部呼叫的功能性方法↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑分隔線↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑


    //如需自定義樣式,可以繼承後重寫下方的方法↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓分隔線↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    /**
     * 使用的佈局
     *
     * @return
     */
    publicintgetLayoutId(){
        return R.layout.refresh_relative_layout;
    }

    /**
     * 頭部容器(如果需要特殊定製,可以做些修改,但建議不要改動頭、尾的容器)
     *
     * @param rlyHead
     * @return
     */
    public RelativeLayout getHeadLayout(RelativeLayout rlyHead){
        return rlyHead;
    }

    /**
     * 下拉重新整理的4種狀態的檢視
     *
     * @param rlyHead
     * @return
     */
    public RelativeLayout getHeadState1Layout(RelativeLayout rlyHead){
        return rlyHead;
    }

    public RelativeLayout getHeadState2Layout(RelativeLayout rlyHead){
        return rlyHead;
    }

    public RelativeLayout getHeadState3Layout(RelativeLayout rlyHead){
        return rlyHead;
    }

    public RelativeLayout getHeadState4Layout(RelativeLayout rlyHead){
        return rlyHead;
    }

    /**
     * 上拉重新整理的4種狀態的檢視
     *
     * @param rlyHead
     * @return
     */
    public RelativeLayout getFootState1Layout(RelativeLayout rlyHead){
        return rlyHead;
    }

    public RelativeLayout getFootState2Layout(RelativeLayout rlyHead){
        return rlyHead;
    }

    public RelativeLayout getFootState3Layout(RelativeLayout rlyHead){
        return rlyHead;
    }

    public RelativeLayout getFootState4Layout(RelativeLayout rlyHead){
        return rlyHead;
    }

    /**
     * 尾部容器(如果需要特殊定製,可以做些修改,但建議不要改動頭、尾的容器)
     *
     * @param rlyFoot
     * @return
     */
    public RelativeLayout getFootLayout(RelativeLayout rlyFoot){
        return rlyFoot;
    }

    /**
     * 回撥動畫的動畫時長,可以根據需求調節快一點慢一點
     * @return
     */
    publicintgetAnimTime(){
        return 760;
    }

    //如需自定義樣式,可以繼承後重寫上方的方法↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑分隔線↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑


    /**
     * 設定下拉的狀態
     *
     * @param state 下拉狀態的值;1-下拉  2-鬆開重新整理  3-正在重新整理  4-重新整理完成
     */
    privatevoidsetPullDownState(int state){
        if (state < 1 || state > 4) {
            Log.e("錯誤","下拉狀態的值越界");
            return;
        }
        pullDownState = state;
        if (onRefreshListener != null && state == PULL_DOWN_STATE_3) {
            //下拉重新整理
            onRefreshListener.onRefresh();
        }
        changePullDownState();
    }

    /**
     * 下拉狀態改變
     */
    privatevoidchangePullDownState(){
        isRefreshing = false;
        rlyHeadState1.setVisibility(INVISIBLE);
        rlyHeadState2.setVisibility(INVISIBLE);
        rlyHeadState3.setVisibility(INVISIBLE);
        rlyHeadState4.setVisibility(INVISIBLE);
        switch (pullDownState) {
            case PULL_DOWN_STATE_1:
                //下拉重新整理
                if (pullDownType != PULL_DOWN_TYPE_NOT_PULL) {
                    rlyHeadState1.setVisibility(VISIBLE);
                }
                break;
            case PULL_DOWN_STATE_2:
                //鬆開重新整理
                if (pullDownType != PULL_DOWN_TYPE_NOT_PULL) {
                    rlyHeadState2.setVisibility(VISIBLE);
                }
                break;
            case PULL_DOWN_STATE_3:
                //正在重新整理
                isRefreshing = true;//除了正在重新整理之外,其他狀態都不在重新整理
                if (pullDownType != PULL_DOWN_TYPE_NOT_PULL) {
                    rlyHeadState3.setVisibility(VISIBLE);
                }
                //無論當前再什麼位置,都跳到正在重新整理的地方
                moveViewAnimation(rlyHead, 0);
                moveViewAnimation(recyclerView, rlyHead.getHeight());
                break;
            case PULL_DOWN_STATE_4:
                //重新整理成功
                if (pullDownType != PULL_DOWN_TYPE_NOT_PULL) {
                    rlyHeadState4.setVisibility(VISIBLE);
                }
                //無論當前再什麼位置,都要跳到初始的位置
                postDelayed(new Runnable() {
                    @Override
                    publicvoidrun(){
                        moveViewAnimation(rlyHead, -1 * rlyHead.getHeight());
                        moveViewAnimation(recyclerView, 0);
                    }
                }, afterRefreshDelayTime);
                break;
        }
    }


    /**
     * 設定下拉的狀態
     *
     * @param state 下拉狀態的值;1-下拉  2-鬆開重新整理  3-正在重新整理  4-重新整理完成
     */
    privatevoidsetPullUpState(int state){
        if (state < 1 || state > 4) {
            Log.e("錯誤","上拉狀態的值越界");
            return;
        }
        pullUpState = state;
        if (onLoadListener != null && state == PULL_UP_STATE_3) {
            //下拉重新整理
            onLoadListener.onLoad();
        }
        changePullUpState();
    }

    /**
     * 下拉狀態改變
     */
    privatevoidchangePullUpState(){
        isLoading = false;
        rlyFootState1.setVisibility(INVISIBLE);
        rlyFootState2.setVisibility(INVISIBLE);
        rlyFootState3.setVisibility(INVISIBLE);
        rlyFootState4.setVisibility(INVISIBLE);
        switch (pullUpState) {
            case PULL_UP_STATE_1:
                //下拉重新整理(自動載入更多的模式下禁止顯示)
                if (pullUpType != PULL_UP_TYPE_LOAD_AUTO && pullUpType != PULL_UP_TYPE_NOT_PULL) {
                    rlyFootState1.setVisibility(VISIBLE);
                }
                break;
            case PULL_UP_STATE_2:
                //鬆開重新整理(自動載入模式下禁止顯示)
                if (pullUpType != PULL_UP_TYPE_LOAD_AUTO && pullUpType != PULL_UP_TYPE_NOT_PULL) {
                    rlyFootState2.setVisibility(VISIBLE);
                }
                break;
            case PULL_UP_STATE_3:
                //正在重新整理
                isLoading = true;//除了正在重新整理之外,其他狀態都不在重新整理
                if (pullUpType != PULL_UP_TYPE_NOT_PULL) {
                    rlyFootState3.setVisibility(VISIBLE);
                }
                //無論當前再什麼位置,都跳到正在重新整理的地方
                moveViewAnimation(rlyFoot, getHeight() - rlyFoot.getHeight());
                moveViewAnimation(recyclerView, rlyFoot.getHeight() * -1);
                break;
            case PULL_UP_STATE_4:
                //重新整理成功
                if (pullUpType != PULL_UP_TYPE_NOT_PULL) {
                    rlyFootState4.setVisibility(VISIBLE);
                }
                //無論當前再什麼位置,都要跳到初始的位置
                postDelayed(new Runnable() {
                    @Override
                    publicvoidrun(){
                        moveViewAnimation(rlyFoot, getHeight());
                        moveViewAnimation(recyclerView, 0);
                    }
                }, afterRefreshDelayTime);
                break;
        }
    }

    /**
     * 記錄三大控制元件的初始位置
     */
    privatevoidrecordLayoutRect(){
        // 記錄三大控制元件的初始位置
        rectRlv.set(recyclerView.getLeft(), 0, recyclerView.getRight(), getHeight());
        rectRlyHead.set(rlyHead.getLeft(), -1 * rlyHead.getHeight(), rlyHead.getRight(), 0);
        rectRlyFoot.set(rlyFoot.getLeft(), getHeight(), rlyFoot.getRight(), getHeight() + rlyFoot.getHeight());
    }

    /**
     * 初始化三大控制元件的位置
     */
    privatevoidinitLayoutRect(){
        post(new Runnable() {
            @Override
            publicvoidrun(){
                //初始化位置
                recyclerView.layout(recyclerView.getLeft(), 0, recyclerView.getRight(), getHeight());
                rlyHead.layout(rlyHead.getLeft(), -1 * rlyHead.getHeight(), rlyHead.getRight(), 0);
                rlyFoot.layout(rlyFoot.getLeft(), getHeight(), rlyFoot.getRight(), getHeight() + rlyFoot.getHeight());

                //繫結一下位置,以免頁面重繪的時候位置發生錯亂
                RelativeLayout.LayoutParams params =
                        (RelativeLayout.LayoutParams) recyclerView.getLayoutParams();
                params.topMargin=0;
                recyclerView.setLayoutParams(params);
                recyclerView.requestLayout();
                params =
                        (RelativeLayout.LayoutParams) rlyHead.getLayoutParams();
                params.topMargin=-1*rlyHead.getHeight();
                rlyHead.setLayoutParams(params);
                rlyHead.requestLayout();
                params =
                        (RelativeLayout.LayoutParams) rlyFoot.getLayoutParams();
                params.topMargin=getHeight();
                params.bottomMargin=getHeight()+rlyFoot.getHeight();
                rlyFoot.setLayoutParams(params);
                rlyFoot.requestLayout();

                //初始化狀態
                setPullDownState(PULL_DOWN_STATE_1);
                setPullUpState(PULL_UP_STATE_1);
            }
        });
    }


    @Override
    publicbooleandispatchTouchEvent(MotionEvent event){
        boolean isPullRecyclerView = false;//如果把頭拉下來了然後再推回上去的時候,必須把recyclerView的觸控事件遮蔽掉,以免列表上移
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isTouching = true;
                startY = (int) event.getY();
                previousY = startY;
                moveHeight = 0;
                recordLayoutRect();
                break;
            case MotionEvent.ACTION_MOVE:
                currentY = (int) event.getY();
                deltaY = currentY - previousY;
                previousY = currentY;
                //判定是否在頂部或者滑到了底部;第二類判定是,正在重新整理什麼的,禁止拖動列表
                if ((!recyclerView.canScrollVertically(-1) && (currentY - startY) > 0) ||
                        (!recyclerView.canScrollVertically(1) && (currentY - startY) < 0) ||
                        (rlyHead.getTop() > rectRlyHead.top && (currentY - startY) > 0) ||
                        (rlyFoot.getTop() < rectRlyFoot.top && (currentY - startY) < 0)) {
                    isPullRecyclerView = true;//下拉或者上啦的時候把recyclerView的觸控事件遮蔽掉
                    //計算阻尼
                    float distance = currentY - startY;
                    if (distance < 0) {
                        distance *= -1;
                    }
                    float damping = 0.5f;//阻尼值
                    float height = getHeight();
                    if (height != 0) {
                        if (distance > height) {
                            damping = 0;
                        } else {
                            damping = (height - distance) / height;
                        }
                    }
                    if (currentY - startY < 0) {
                        damping = 1 - damping;
                    }

                    //阻力值限制再0.3-0.5之間,平滑過度
                    damping *= 0.25;
                    damping += 0.25;

                    moveHeight = moveHeight + (deltaY * damping);
                    recyclerView.layout(rectRlv.left, (int) (rectRlv.top + moveHeight), rectRlv.right,
                            (int) (rectRlv.bottom + moveHeight));
                    rlyHead.layout(rectRlyHead.left, (int) (rectRlyHead.top + moveHeight), rectRlyHead.right,
                            (int) (rectRlyHead.bottom + moveHeight));
                    rlyFoot.layout(rectRlyFoot.left, (int) (rectRlyFoot.top + moveHeight), rectRlyFoot.right,
                            (int) (rectRlyFoot.bottom + moveHeight));

                    //判定是否是下拉動作並處於可以下拉重新整理狀態
                    if (pullDownType == PULL_DOWN_TYPE_REFRESH && moveHeight > 0) {
                        if (moveHeight > rlyHead.getHeight()) {
                            setPullDownState(PULL_DOWN_STATE_2);
                        } else {
                            setPullDownState(PULL_DOWN_STATE_1);
                        }
                    }

                    //判定是否是上拉動作並且處於上啦重新整理狀態
                    if (pullUpType == PULL_UP_TYPE_LOAD_PULL && moveHeight < 0) {
                        if (moveHeight * -1 > rlyFoot.getHeight()) {
                            setPullUpState(PULL_UP_STATE_2);
                        } else {
                            setPullUpState(PULL_UP_STATE_1);
                        }
                    }

                    //將當前拖動的高度回撥
                    if (onTouchHeightListener != null) {
                        //需要列表處於到頂的狀態
                        if (!recyclerView.canScrollVertically(-1) && moveHeight >= 1) {
                            onTouchHeightListener.onTouchHeight((int) moveHeight);
                        }
                        //需要列表處於到底的狀態
                        if (!recyclerView.canScrollVertically(1) && moveHeight <= -1) {
                            onTouchHeightListener.onTouchHeight((int) moveHeight);
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                isTouching = false;
                //判定是否是下拉動作並處於可以下拉重新整理狀態
                if (pullDownType =