下拉刷新、上拉加載更多控件實現原理及解析(二)

    以前的博客《下拉刷新、上拉加載更多控件實現原理及解析》中實現了一個通用的刷新控件,可是使用中發現了問題,當包含的列表中有嵌套滾動(滾動控件中還包含滾動控件)時,會出現滾動衝突。java

緣由分析

    由於咱們直接攔截了「dispatchTouchEvent」,這個回調是不能被子控件控制的,因此當子控件須要父控件讓出Touch事件時(好比調用父控件的「requestDisallowInterceptTouchEvent(true)」方法),咱們如今的實現是達不到的,咱們須要換一個回調接口,去實現咱們的功能。ide

尋找合適的函數

咱們如今有兩個需求:

一、可以攔截Touch事件;

    可以攔截Touch事件的函數,除了咱們前面用到的「dispatchTouchEvent」,還有就是「onInterceptTouchEvent」,這個函數是須要和「onTouchEvent」配合使用的。函數

    「onInterceptTouchEvent」攔截觸摸事件的意思,只要你在該函數中一直返回false(ViewGroup的默認實現是返回false的),後續的Touch事件會一直先給這個函數;一旦你在該函數中返回true,那該函數就再也收不到後續的Touch事件,而是傳給它的「onTouchEvent」函數,「onTouchEvent」返回false表示不消耗Touch事件,返回true則消耗Touch事件。優化

二、子控件可控;

    「requestDisallowInterceptTouchEvent」函數用來子控件不想父控件打斷它的Touch事件。spa

優化代碼

結合前面的分析,咱們把相關代碼修改以下:code

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if ((!mPullRefreshEnable && !mPullLoadEnable) || isRefreshing) {
        return super.onInterceptTouchEvent(ev);
    }

    switch (ev.getActionMasked()) {
        case MotionEvent.ACTION_DOWN: {
            if (refreshLayoutController != null) {
                mPullRefreshEnable = refreshLayoutController.isPullRefreshEnable();
                mPullLoadEnable = refreshLayoutController.isPullLoadEnable();
            }
            preY = ev.getY();
            preX = ev.getX();
            actionDetermined = false;
            return super.onInterceptTouchEvent(ev);
        }

        case MotionEvent.ACTION_MOVE: {
            float currentY = ev.getY();
            float currentX = ev.getX();
            float dy = currentY - preY;
            float dx = currentX - preX;
            preY = currentY;
            preX = currentX;
            if (!actionDetermined) {
                actionDetermined = true;
                //判斷是下拉刷新仍是上拉加載更多
                if (dy > 0 && !canChildScrollUp() && mPullRefreshEnable) {
                    mCurrentAction = ACTION_PULL_DOWN_REFRESH;
                } else if (dy < 0 && !canChildScrollDown() && mPullLoadEnable) {
                    mCurrentAction = ACTION_PULL_UP_LOAD_MORE;
                } else {
                    mCurrentAction = -1;
                }
            }

            if (mCurrentAction != -1) {
                return true;
            } else {
                return super.onInterceptTouchEvent(ev);
            }
        }

        default: {
            return super.onInterceptTouchEvent(ev);
        }
    }
}
@Override
public boolean onTouchEvent(MotionEvent event) {
    if ((!mPullRefreshEnable && !mPullLoadEnable) || isRefreshing) {
        return false;
    }

    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_MOVE: {
            float currentY = event.getY();
            float currentX = event.getX();
            float dy = currentY - preY;
            float dx = currentX - preX;
            preY = currentY;
            preX = currentX;
            handleScroll(dy);
            observerArriveBottom();
            return true;
        }

        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL: {
            return releaseTouch();
        }

        default: {
            return super.onTouchEvent(event);
        }
    }

}

解決嵌套

    當須要嵌套滾動時,須要複寫你子控件的「onTouch」函數:server

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
        ((ViewGroup) getParent()).requestDisallowInterceptTouchEvent(true);
    } else if (ev.getActionMasked() == MotionEvent.ACTION_UP
            || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
        ((ViewGroup) getParent()).requestDisallowInterceptTouchEvent(false);
    }
    return super.onTouchEvent(ev);
}
相關文章
相關標籤/搜索