美文网首页
Android_View的Touch源码浅析

Android_View的Touch源码浅析

作者: 放纵的卡尔 | 来源:发表于2018-02-14 15:35 被阅读0次

1.当一个view的clickabe是true的时候,那么所有的事件都会自动消费.return true.

2.DOWN_MOVE_UP三个事件是连续传递的,在哪一层消费了down事件,那么move事件就会在哪一层消费.同理MOVE和UP;由于move是连续的,即使move没有renturn true,由于down是在这一层消费的,那么所有的move还是会在这一层消费(但是会向上传递到最外层的父类,只传递到最外层的父类,并不是层层传递的,并且会消费up在最外层的父类因为是在最外层的父类消费的move,即使中间有view move消费true,但是并不会执行,因为是根据down在哪一层消费的) QQ截图20180214153310.png QQ图片20180214153349.png

最近研究了一下touch的源代码,毕竟很多东西还是需要从源码理解才更深刻.

public boolean dispatchTouchEvent(MotionEvent ev) {
    final int action = ev.getAction();  
    final float xf = ev.getX();  
    final float yf = ev.getY();  
    final float scrolledXFloat = xf + mScrollX;  
    final float scrolledYFloat = yf + mScrollY;  
    final Rect frame = mTempRect;  
    boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  
    if (action == MotionEvent.ACTION_DOWN) {  
        if (mMotionTarget != null) {  
            mMotionTarget = null;  
        }

/*
        //允许||不拦截  false  ||  true 执行
        //不允许||不拦截  true||true   执行
        //允许 ||拦截     false|| false  不执行
        //不允许||拦截   true||false  执行

        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
        // We're already in this state, assume our ancestors are too
        return;
        }*/

        if (disallowIntercept || !onInterceptTouchEvent(ev)) {  
            ev.setAction(MotionEvent.ACTION_DOWN);  
            final int scrolledXInt = (int) scrolledXFloat;  
            final int scrolledYInt = (int) scrolledYFloat;  
            final View[] children = mChildren;  
            final int count = mChildrenCount;  
            for (int i = count - 1; i >= 0; i--) { //down-->事件 子类消费掉,那么down事件就结束了.
                final View child = children[i];  
                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE  
                        || child.getAnimation() != null) {  
                    child.getHitRect(frame);  
                    if (frame.contains(scrolledXInt, scrolledYInt)) {  
                        final float xc = scrolledXFloat - child.mLeft;  
                        final float yc = scrolledYFloat - child.mTop;  
                        ev.setLocation(xc, yc);  
                        child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
                        if (child.dispatchTouchEvent(ev))  {  
                            mMotionTarget = child;  
                            return true;  
                        }  
                    }  
                }  
            }  
        }  
    }  
    boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||  
            (action == MotionEvent.ACTION_CANCEL);  
    if (isUpOrCancel) {  
        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;  //因为发出了cancle
    }  
    final View target = mMotionTarget;  
    if (target == null) {  //down事件-->子类没消费掉事件(或者没子类),那么所有的事件都执行到这了. 只执行viewGroup本身的onTouchEvent事件.
                           //  这个ViewGroup所有的事件在这里肯定会消费掉!或者根本就不会执行move事件了,因为没有拦截,直接去执行下面的代码了!
        ev.setLocation(xf, yf);  
        if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
            ev.setAction(MotionEvent.ACTION_CANCEL);  
            mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
        }  
        return super.dispatchTouchEvent(ev);  
    }
    //下面的是子类消费掉事件了-->那么target就不是空的了,就会执行到这了.
    if (!disallowIntercept && onInterceptTouchEvent(ev)) {          //允许拦截并且拦截了
        final float xc = scrolledXFloat - (float) target.mLeft;  
        final float yc = scrolledYFloat - (float) target.mTop;  
        mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
        ev.setAction(MotionEvent.ACTION_CANCEL);  
        ev.setLocation(xc, yc);                     //-->更改事件为cancle事件,这次再次置空mMotionTarget;再去执行73行的代码.开始执行move操作.
        if (!target.dispatchTouchEvent(ev)) {       //执行cancle的事件;被拦截的控件的canle事件;因为target还是他!
        }  
        mMotionTarget = null;  
        return true;  
    }  
    if (isUpOrCancel) {  
        mMotionTarget = null;  
    }  
    final float xc = scrolledXFloat - (float) target.mLeft;  
    final float yc = scrolledYFloat - (float) target.mTop;  
    ev.setLocation(xc, yc);  
    if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {  
        ev.setAction(MotionEvent.ACTION_CANCEL);  
        target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
        mMotionTarget = null;  
    }  
    return target.dispatchTouchEvent(ev);  //没有拦截到的话,就这里执行子类的move  up
}

相关文章

网友评论

      本文标题:Android_View的Touch源码浅析

      本文链接:https://www.haomeiwen.com/subject/vbyetftx.html