事件分发

来源:互联网 发布:scrollreveal.js 教程 编辑:程序博客网 时间:2024/05/30 23:38

     我们直接对比ViewGroup和view的dispatchTouchEvent方法来理解touch事件的分发。

如下是ViewGroupdispatchTouchEvent方法:

//ViewGroup中的dispatchTouchEventpublic 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;    //如果是ACTION_DOWN这个动作的话,就会mMotionTarget设为null,来重新寻找目标view    if (action == MotionEvent.ACTION_DOWN) {        if (mMotionTarget != null) {            mMotionTarget = null;        }        //disallowIntercept是否禁用拦截功能,onInterceptTouchEvent:是否拦截        //1.如果禁用了拦截即disallowIntercept为true,或者没有禁用,但是没有拦截,        //就会进入if之内寻找需要消费此touch事件的子view了        //2.如果拦截了,则不会进入此if中,则直接到64行执行        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--) {                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;                      //如果此处有其中一个子view的dispatchTouchEvent返回true,那么就把                      //此子view当做mMotionTarget                        if (child.dispatchTouchEvent(ev))  {                            mMotionTarget = child;                            return true;                        }                    }                }            }        }    }//end action == MotionEvent.ACTION_DOWN            boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||            (action == MotionEvent.ACTION_CANCEL);    if (isUpOrCancel) {        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;    }    final View target = mMotionTarget;    if (target == null) {        ev.setLocation(xf, yf);        if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {            ev.setAction(MotionEvent.ACTION_CANCEL);            mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;        }        //如果第37行没有成立,即当前viewgroup的所有子view的dispatchTouchEvent        //都返回false,那么就是没找到mMotionTarget,即mMotionTarget为null,在        //此情况下就会执行此句,也是View中的dispatchTouchEvent方法了,因为所有的        //ViewGroup的父类都是View,view的dispatchTouchEvent可以参考下一个方法。        return super.dispatchTouchEvent(ev);    }        //如果是允许拦截,而且拦截了    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);        if (!target.dispatchTouchEvent(ev)) {        }        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;    }    //如果mMotionTarget不为空,那么move和up事件直接交给其处理    return target.dispatchTouchEvent(ev);}


如下是View的dispatchTouchEvent方法:

/* 此处为view的dispatchTouchEvent方法 * 如果此方法返回true,那么如上ViewGroup中的dispatchTouchEvent方法 * 的mMotionTarget就不为空了 *  * */public boolean dispatchTouchEvent(MotionEvent event) {    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&            mOnTouchListener.onTouch(this, event)) {        return true;    }    return onTouchEvent(event);}



通过如上源码可以了解到,在viewgroup的dispatchTouchEvent方法的调用流程中,是先会去调用onInterceptTouchEvent方法(19行),

如果onInterceptTouchEvent返回为false,也就是不拦截的话,会把此touch事件分发给此viewgroup的所有子view(37行);在此情况之下,如果所有的子view的dispatchTouchEvent返回的都是false,那么mMotionTarget为null,就会执行到64行,super.dispatchTouchEvent(ev),也就是View中的dispatchTouchEvent方法了,因为所有的ViewGroup的父类都是View,view的dispatchTouchEvent可以参考第二个方法,如果有子view的dispatchTouchEvent方法返回true,那么就把他赋值给mMotionTarget,那么下次move和up事件来的时候直接交给其处理(91行)

如果onInterceptTouchEvent返回为true,也就是ViewGroup拦截此次touch事件,那么就不会进入if判断语句的内部,而会执行到64行。


总结来说,如果onInterceptTouchEvent为false但是所有的子view的dispatchTouchEvent都返回false,或者是直接拦截,在这两种情况之下,都会执行到64行,super.dispatchTouchEvent(ev),而此行也就是父类的dispatchTouchEvent方法,参考方法二。


看如下伪代码:

View mTarget=null;//保存捕获Touch事件处理的View    public boolean dispatchTouchEvent(MotionEvent ev) {        //....其他处理,在此不管                if(ev.getAction()==KeyEvent.ACTION_DOWN){            //每次Down事件,都置为Null            if(!onInterceptTouchEvent()){            mTarget=null;            View[] views=getChildView();            for(int i=0;i<views.length;i++){                if(views[i].dispatchTouchEvent(ev))                    mTarget=views[i];                    return true;            }          }        }        //当子View没有捕获down事件时,ViewGroup自身处理。        //此时把此ViewGroup当做一个view来看待        //这里处理的Touch事件包含Down、Up和Move        if(mTarget==null){            return super.dispatchTouchEvent(ev);        }        //...其他处理,在此不管        if(onInterceptTouchEvent()){         //...其他处理,在此不管             }         //当子View捕获了down事件时,mTarget不为空,那么Move和UP直接交给mTarget处理//这一步在Action_Down中是不会执行到的,只有Move和UP才会执行到。        return mTarget.dispatchTouchEvent(ev);    }
此处的伪代码是viewgroup的dispatchTouchEvent方法的简化,可以很清楚的看到有子view消费事件和没有子view消费事件的流程

参考如下资料:

http://www.cnblogs.com/linjzong/p/4191891.html

http://blog.csdn.net/guolin_blog/article/details/9097463

http://blog.csdn.net/lmj623565791/article/details/39102591

同时可以验证

http://blog.csdn.net/chdjj/article/details/22910581

0 0
原创粉丝点击