天天看點

View滑動沖突

當我們内外兩層View都可以滑動時候,就會産生滑動沖突!

View滑動沖突
  • 1.外層與内層滑動方向不一緻,外層ViewGroup是可以橫向滑動的,内層View是可以豎向滑動的(類似ViewPager,每個頁面裡面是ListView)
  • 2.外層與内層滑動方向一緻,外層ViewGroup是可以豎向滑動的,内層View同樣也是豎向滑動的(類似ScrollView包裹ListView)

注: 一場景有外部處理和内部處理兩種發誓,二場景主要看邏輯實作

解決方案有兩種,外部處理和内部處理

外部攔截法:
// 外層view 的  onInterceptTouchEvent
 private int mLastX;
 private int mLastY;
@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercepted = false;
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        final int action = ev.getAction() & MotionEvent.ACTION_MASK;
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                intercepted = false;
                //調用ViewPager的onInterceptTouchEvent方法初始化mActivePointerId
                super.onInterceptTouchEvent(ev);
                break;
            case MotionEvent.ACTION_MOVE:
                //橫坐标位移增量
                int deltaX = x - mLastXIntercept;
                //縱坐标位移增量
                int deltaY = y - mLastYIntercept;
                if (Math.abs(deltaX)>Math.abs(deltaY)){
                    intercepted = true;
                }else{
                    intercepted = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                intercepted = false;
                break;
            default:
                break;
        }

        mLastXIntercept = x;
        mLastYIntercept = y;

        LogUtil.e(TAG,"intercepted = "+intercepted);
        return intercepted;
    }
           

Math.abs(deltaX)>Math.abs(deltaY)表示橫向位移增量大于豎向位移增量,即水準滑動,則攔截事件。

注意:

  • ACTION_DOWN 一定傳回false,不要攔截它,否則根據View事件分發機制,後續ACTION_MOVE 與 ACTION_UP事件都将預設交給父View去處理!
  • 原則上ACTION_UP也需要傳回false,如果傳回true,并且滑動事件交給子View處理,那麼子View将接收不到ACTION_UP事件,子View的onClick事件也無法觸發。而父View不一樣,如果父View在ACTION_MOVE中開始攔截事件,那麼後續ACTION_UP也将預設交給父View處理!
private int mLastX;
 private int mLastY;
    
// 内層view 的  onInterceptTouchEvent
@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int x = (int) ev.getX();
        int y = (int) ev.getY();

        final int action = ev.getAction() & MotionEvent.ACTION_MASK;
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                //水準移動的增量
                int deltaX = x - mLastX;
                //豎直移動的增量
                int deltaY = y - mLastY;
                //當水準增量大于豎直增量時,表示水準滑動,此時需要父View去處理事件
                if (Math.abs(deltaX) > Math.abs(deltaY)){
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        mLastX = x;
        mLastY = y;
        return super.dispatchTouchEvent(ev);
    }
           
// 外層view 的  onInterceptTouchEvent
@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction() & MotionEvent.ACTION_MASK;
        if (action == MotionEvent.ACTION_DOWN){
            super.onInterceptTouchEvent(ev);
            return false;
        }
        return true;
    }
           

繼續閱讀