美文网首页
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