Android触摸事件分发机制详解

来源:互联网 发布:买家淘宝定制商品 编辑:程序博客网 时间:2024/05/17 03:04
  • dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()方法源码解析
  • 各种触摸事件分发、消费情况详解

dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()方法源码解析

  Android触摸事件分发过程中最重要的就是dispatchTouchEvent()onInterceptTouchEvent()onTouchEvent()方法。其中onInterceptTouchEvent()方法只存在于ViewGroup中,View中没有,其用于事件的拦截。dispatchTouchEvent()方法用于事件的分发,onTouchEvent()方法用于事件的消费。
  下面给出这三个主要方法的部分主要源码实现,并做出分析。
  ViewGroup的dispatchTouchEvent方法中有下面这段代码:

final boolean intercepted;        if (actionMasked == MotionEvent.ACTION_DOWN                || mFirstTouchTarget != null) {            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;            if (!disallowIntercept) {                intercepted = onInterceptTouchEvent(ev);                ev.setAction(action); // restore action in case it was changed            } else {                intercepted = false;            }        } else {            // There are no touch targets and this action is not an initial down            // so this view group continues to intercept touches.            intercepted = true;        }

  这段代码用来判断是否拦截该事件,从代码中可知,当触发down事件或已存在之前消费过事件的对象时,需要通过disallowInterceptonInterceptTouchEvent(ev)两个条件来判断是否要拦截该事件。其中disallowIntercept默认得到的值为false,即允许拦截,其值可通过requestDisallowInterceptTouchEvent方法设置,当disallowIntercept为false时,接下来调用onInterceptTouchEvent(ev)方法进行判断。所以可通过重写onInterceptTouchEvent(ev)方法对各种事件进行具体的事件拦截。
  dispatchTouchEvent中还会间接调用到如下代码段:

// Perform any necessary transformations and dispatch.        if (child == null) {            handled = super.dispatchTouchEvent(transformedEvent);        } else {            final float offsetX = mScrollX - child.mLeft;            final float offsetY = mScrollY - child.mTop;            transformedEvent.offsetLocation(offsetX, offsetY);            if (! child.hasIdentityMatrix()) {                transformedEvent.transform(child.getInverseMatrix());            }            handled = child.dispatchTouchEvent(transformedEvent);        }

  这段代码展示了,ViewGroup的dispatchTouchEvent会调用其子视图的dispatchTouchEvent方法,将事件向下分发。
  事件以上面的形式,一层层向内传递,若未经拦截,到达View的dispatchTouchEvent方法时,其中有下面一段代码:

//noinspection SimplifiableIfStatement            ListenerInfo li = mListenerInfo;            if (li != null && li.mOnTouchListener != null                    && (mViewFlags & ENABLED_MASK) == ENABLED                    && li.mOnTouchListener.onTouch(this, event)) {                result = true;            }            if (!result && onTouchEvent(event)) {                result = true;            }

  这段代码中,有一个很长的判定条件,其结果决定了是否执行onTouchEvent方法。首先我们看mOnTouchListener在哪进行设置,找到如下代码:

public void setOnTouchListener(OnTouchListener l) {        getListenerInfo().mOnTouchListener = l;    }
ListenerInfo getListenerInfo() {        if (mListenerInfo != null) {            return mListenerInfo;        }        mListenerInfo = new ListenerInfo();        return mListenerInfo;    }

  所以当对视图调用setOnTouchListener方法设置监听后,li != null && li.mOnTouchListener != null两个条件就得到了满足,而(mViewFlags & ENABLED_MASK) == ENABLED的判断是该视图是否处于enable状态,其默认为true,所以当OnTouchListener中的onTouch方法返回true时,就拦截了事件向onTouchEvent方法传递。下面看一下View的onTouchEvent方法中都执行了一些什么操作:

public boolean onTouchEvent(MotionEvent event) {        final float x = event.getX();        final float y = event.getY();        final int viewFlags = mViewFlags;        final int action = event.getAction();        if ((viewFlags & ENABLED_MASK) == DISABLED) {            if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {                setPressed(false);            }            // A disabled view that is clickable still consumes the touch            // events, it just doesn't respond to them.            return (((viewFlags & CLICKABLE) == CLICKABLE                    || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)                    || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);        }        if (mTouchDelegate != null) {            if (mTouchDelegate.onTouchEvent(event)) {                return true;            }        }        if (((viewFlags & CLICKABLE) == CLICKABLE ||                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||                (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {            switch (action) {                case MotionEvent.ACTION_UP:                    boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {                        // take focus if we don't have it already and we should in                        // touch mode.                        boolean focusTaken = false;                        if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {                            focusTaken = requestFocus();                        }                        if (prepressed) {                            // The button is being released before we actually                            // showed it as pressed.  Make it show the pressed                            // state now (before scheduling the click) to ensure                            // the user sees it.                            setPressed(true, x, y);                       }                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {                            // This is a tap, so remove the longpress check                            removeLongPressCallback();                            // Only perform take click actions if we were in the pressed state                            if (!focusTaken) {                                // Use a Runnable and post this rather than calling                                // performClick directly. This lets other visual state                                // of the view update before click actions start.                                if (mPerformClick == null) {                                    mPerformClick = new PerformClick();                                }                                if (!post(mPerformClick)) {                                    performClick();                                }                            }                        }                        if (mUnsetPressedState == null) {                            mUnsetPressedState = new UnsetPressedState();                        }                        if (prepressed) {                            postDelayed(mUnsetPressedState,                                    ViewConfiguration.getPressedStateDuration());                        } else if (!post(mUnsetPressedState)) {                            // If the post failed, unpress right now                            mUnsetPressedState.run();                        }                        removeTapCallback();                    }                    mIgnoreNextUpEvent = false;                    break;                case MotionEvent.ACTION_DOWN:                    mHasPerformedLongPress = false;                    if (performButtonActionOnTouchDown(event)) {                        break;                    }                    // Walk up the hierarchy to determine if we're inside a scrolling container.                    boolean isInScrollingContainer = isInScrollingContainer();                    // For views inside a scrolling container, delay the pressed feedback for                    // a short period in case this is a scroll.                    if (isInScrollingContainer) {                        mPrivateFlags |= PFLAG_PREPRESSED;                        if (mPendingCheckForTap == null) {                            mPendingCheckForTap = new CheckForTap();                        }                        mPendingCheckForTap.x = event.getX();                        mPendingCheckForTap.y = event.getY();                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());                    } else {                        // Not inside a scrolling container, so show the feedback right away                        setPressed(true, x, y);                        checkForLongClick(0);                    }                    break;                case MotionEvent.ACTION_CANCEL:                    setPressed(false);                    removeTapCallback();                    removeLongPressCallback();                    mInContextButtonPress = false;                    mHasPerformedLongPress = false;                    mIgnoreNextUpEvent = false;                    break;                case MotionEvent.ACTION_MOVE:                    drawableHotspotChanged(x, y);                    // Be lenient about moving outside of buttons                    if (!pointInView(x, y, mTouchSlop)) {                        // Outside button                        removeTapCallback();                        if ((mPrivateFlags & PFLAG_PRESSED) != 0) {                            // Remove any future long press/tap checks                            removeLongPressCallback();                            setPressed(false);                        }                    }                    break;            }            return true;        }        return false;    }

  方法很长,其中定义了对down,move,up等事件的处理。我们知道如果在视图上设置了OnTouchListener并在其onTouch方法中返回true,该视图的onClick方法将不再被触发,我们还知道,onClick方法在up事件时被触发。我们查看上述代码对up事件的处理时,发现有一个performClick方法,该方法的代码如下:

public boolean performClick() {        final boolean result;        final ListenerInfo li = mListenerInfo;        if (li != null && li.mOnClickListener != null) {            playSoundEffect(SoundEffectConstants.CLICK);            li.mOnClickListener.onClick(this);            result = true;        } else {            result = false;        }        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);        return result;    }

  是不是看到了li.mOnClickListener.onClick(this)这行代码,这就是onClick被触发回调的方法,通过上面的分析知道,如果设置的OnTouchListener的onTouch方法中返回true,则将不会执行到这段回调代码,所以导致onClick方法失效。
  所以总体上,当一个触摸事件开始时,最外层ViewGroup捕获该事件,并开始调用其dispatchTouchEvent方法进行事件分发,该方法会根据本次触摸的之前事件的拦截和消费情况,来决定怎样调用其内层的ViewGroup的dispatchTouchEventonInterceptTouchEventonTouchEvent方法或View的dispatchTouchEventonTouchEvent方法,来将事件更深层的分发和消费,这些方法的处理结果,又逐级回传,从而进一步影响后面事件的分发和消费方式。
  接下来,以上面的源码分析为基础,具体分析触摸事件分发处理情况。

各种触摸事件分发、消费情况详解

ACTION_DOWN事件未被消费,分发失败

  在一个触摸事件中,down事件起着至关重要的作用,down事件就是“敲门”事件,如果门没有敲开,后面的事件也就没有意义了,所以如果down事件没有被分发出去,即没有被消费,那么后面的事件也就不会被分发了。
这里写图片描述

说明:

  • 都不拦截ACTION_DOWN事件,会依次向下传递
  • 都不消费ACTION_DOWN事件,onTouchEvent会依次向上传递
  • 都不消费ACTION_DOWN事件,dispatchTouchEvent会返回false,表示事件没有被派发出去
  • ACTION_DOWN事件没有被消费,后续的ACTION_MOVE、ACTION_UP等事件都不会再被传递

示例程序:

Override    public boolean dispatchTouchEvent(MotionEvent ev) {        int action = ev.getAction();        String motionEvent = null;        switch (action) {            case MotionEvent.ACTION_DOWN:                motionEvent = "down";                return false;            case MotionEvent.ACTION_MOVE:                motionEvent = "move";                break;            case MotionEvent.ACTION_UP:                motionEvent = "up";                break;            case MotionEvent.ACTION_CANCEL:                motionEvent = "cancel";                break;        }        Log.i(SXD, TAG + "--dispatchTouchEvent++in++motionEvent:" + motionEvent);        boolean ret = super.dispatchTouchEvent(ev);        Log.i(SXD, TAG + "--dispatchTouchEvent++out++ret:" + ret + ",motionEvent:" + motionEvent);        return ret;    }

  该程序没有log输出,则证明down事件没有分发成功后,在没有后续事件进行分发。

ACTION_DOWN事件被消费,后续事件被拦截

  如果视图消费了down事件,且之后有事件被拦截,则每种被拦截事件类型(move,up等)都会触发收到一次cancel事件。
这里写图片描述

示例程序:

onInterceptTouchEvent在Move事件返回true
Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        int action = ev.getAction();        String motionEvent = null;        switch (action) {            case MotionEvent.ACTION_DOWN:                motionEvent = "down";                break;            case MotionEvent.ACTION_MOVE:                motionEvent = "move";                return true;            case MotionEvent.ACTION_UP:                motionEvent = "up";                break;            case MotionEvent.ACTION_CANCEL:                motionEvent = "cancel";                break;        }        Log.i(SXD, TAG + "--onInterceptTouchEvent++in++motionEvent:" + motionEvent);        boolean ret = super.onInterceptTouchEvent(ev);        Log.i(SXD, TAG + "--onInterceptTouchEvent++out++ret:" + ret + ",motionEvent:" + motionEvent);        return ret;    }
I/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouch++ret:false,motionEvent:downI/sxd: TouchButton--onTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:cancelI/sxd: TouchButton--onTouch++ret:false,motionEvent:cancelI/sxd: TouchButton--onTouchEvent++in++motionEvent:cancelI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:cancelI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:cancelI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:upI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:upI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:up

  结果表明,当onInterceptTouchEvent在move事件时返回true进行事件拦截时,之前的down事件可以向下分发,但第一次的move事件将触发之前处理down事件的子View触发cancel事件,且本次move事件不会被拦截层消费,但之后的move,up等事件可被拦截层消费。

onInterceptTouchEvent在Up事件返回true
@Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        int action = ev.getAction();        String motionEvent = null;        switch (action) {            case MotionEvent.ACTION_DOWN:                motionEvent = "down";                break;            case MotionEvent.ACTION_MOVE:                motionEvent = "move";                break;            case MotionEvent.ACTION_UP:                motionEvent = "up";                return true;            case MotionEvent.ACTION_CANCEL:                motionEvent = "cancel";                break;        }        Log.i(SXD, TAG + "--onInterceptTouchEvent++in++motionEvent:" + motionEvent);        boolean ret = super.onInterceptTouchEvent(ev);        Log.i(SXD, TAG + "--onInterceptTouchEvent++out++ret:" + ret + ",motionEvent:" + motionEvent);        return ret;    }
I/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouch++ret:false,motionEvent:downI/sxd: TouchButton--onTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouch++ret:false,motionEvent:moveI/sxd: TouchButton--onTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouch++ret:false,motionEvent:moveI/sxd: TouchButton--onTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouch++ret:false,motionEvent:moveI/sxd: TouchButton--onTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:upI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:cancelI/sxd: TouchButton--onTouch++ret:false,motionEvent:cancelI/sxd: TouchButton--onTouchEvent++in++motionEvent:cancelI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:cancelI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:cancelI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:up

  结果表明,当onInterceptTouchEvent在up事件时返回true进行事件拦截时,之前的触摸事件可以向下分发,但本次up事件将触发之前处理事件的子View触发cancel事件,且本次cancel事件不会被拦截层消费。

ACTION_DOWN事件被拦截

  如果视图没有消费down事件,则之后的事件不会再向其分发。
这里写图片描述

示例程序:

初始down事件被上层拦截
@Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        int action = ev.getAction();        String motionEvent = null;        switch (action) {            case MotionEvent.ACTION_DOWN:                motionEvent = "down";                return true;            case MotionEvent.ACTION_MOVE:                motionEvent = "move";                break;            case MotionEvent.ACTION_UP:                motionEvent = "up";                break;            case MotionEvent.ACTION_CANCEL:                motionEvent = "cancel";                break;        }        Log.i(SXD, TAG + "--onInterceptTouchEvent++in++motionEvent:" + motionEvent);        boolean ret = super.onInterceptTouchEvent(ev);        Log.i(SXD, TAG + "--onInterceptTouchEvent++out++ret:" + ret + ",motionEvent:" + motionEvent);        return ret;    }
I/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:downI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:upI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:upI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:upI/sxd: TouchTestRelativeLayout--onClick
View未消费down事件
@Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        String motionEvent = null;        switch (action) {            case MotionEvent.ACTION_DOWN:                motionEvent = "down";                return false;            case MotionEvent.ACTION_MOVE:                motionEvent = "move";                break;            case MotionEvent.ACTION_UP:                motionEvent = "up";                break;            case MotionEvent.ACTION_CANCEL:                motionEvent = "cancel";                break;        }        Log.i(SXD, TAG + "--onTouchEvent++in++motionEvent:" + motionEvent);        boolean ret = super.onTouchEvent(event);        Log.i(SXD, TAG + "--onTouchEvent++out++ret:" + ret + ",motionEvent:" + motionEvent);        return ret;    }
I/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouch++ret:false,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++out++ret:false,motionEvent:downI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:downI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onTouch++ret:false,motionEvent:upI/sxd: TouchTestRelativeLayout--onTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onTouchEvent++out++ret:true,motionEvent:upI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:upI/sxd: TouchTestRelativeLayout--onClick

  结果表明,当视图没有消费down事件,则其后的所有事件都不会再分发给它,但会触发一次该视图的onTouch方法。

事件被消费后,不再上传

  只要视图消费了down事件,则不管其后续事件是否消费,只要不被拦截,则所有事件都会被分发到这里。且被下层消费了的事件,不会再被上层消费。
这里写图片描述

示例代码:

onTouchEvent未消费Move事件
@Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        String motionEvent = null;        switch (action) {            case MotionEvent.ACTION_DOWN:                motionEvent = "down";                break;            case MotionEvent.ACTION_MOVE:                motionEvent = "move";                return false;            case MotionEvent.ACTION_UP:                motionEvent = "up";                break;            case MotionEvent.ACTION_CANCEL:                motionEvent = "cancel";                break;        }        Log.i(SXD, TAG + "--onTouchEvent++in++motionEvent:" + motionEvent);        boolean ret = super.onTouchEvent(event);        Log.i(SXD, TAG + "--onTouchEvent++out++ret:" + ret + ",motionEvent:" + motionEvent);        return ret;    }
I/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouch++ret:false,motionEvent:downI/sxd: TouchButton--onTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouch++ret:false,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouch++ret:false,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:upI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:upI/sxd: TouchButton--onTouch++ret:false,motionEvent:upI/sxd: TouchButton--onTouchEvent++in++motionEvent:upI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:upI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:upI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:upI/sxd: TouchButton--onClick

  结果表明,只要视图消费掉了down事件,且上层分发不再拦截,则其后的所有事件都会再分发给它,且其消费不对后续事件消费时,仅会触发其当前事件的onTouch方法。

onTouchEvent未消费Up事件
@Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        String motionEvent = null;        switch (action) {            case MotionEvent.ACTION_DOWN:                motionEvent = "down";                break;            case MotionEvent.ACTION_MOVE:                motionEvent = "move";                break;            case MotionEvent.ACTION_UP:                motionEvent = "up";                return false;            case MotionEvent.ACTION_CANCEL:                motionEvent = "cancel";                break;        }        Log.i(SXD, TAG + "--onTouchEvent++in++motionEvent:" + motionEvent);        boolean ret = super.onTouchEvent(event);        Log.i(SXD, TAG + "--onTouchEvent++out++ret:" + ret + ",motionEvent:" + motionEvent);        return ret;    }
I/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:downI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouch++ret:false,motionEvent:downI/sxd: TouchButton--onTouchEvent++in++motionEvent:downI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:downI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:moveI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouch++ret:false,motionEvent:moveI/sxd: TouchButton--onTouchEvent++in++motionEvent:moveI/sxd: TouchButton--onTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchButton--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:true,motionEvent:moveI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++in++motionEvent:upI/sxd: TouchTestRelativeLayout--onInterceptTouchEvent++out++ret:false,motionEvent:upI/sxd: TouchButton--dispatchTouchEvent++in++motionEvent:upI/sxd: TouchButton--onTouch++ret:false,motionEvent:upI/sxd: TouchButton--dispatchTouchEvent++out++ret:false,motionEvent:upI/sxd: TouchTestRelativeLayout--dispatchTouchEvent++out++ret:false,motionEvent:up

  结果表明,只要视图消费掉了down事件,且上层分发不再拦截,则其后的所有事件都会再分发给它,且其消费不对后续事件消费时,仅会触发其当前事件的onTouch方法。

2 0
原创粉丝点击