touch事件与MotionEvent(一)

来源:互联网 发布:手机应用编程 编辑:程序博客网 时间:2024/06/16 12:58

onInterceptTouchEvent()

返回值说明:
<span style="font-size:24px;">   </span><span style="font-size:18px;">For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().    If you return true from here, you will not receive any following events: the target view will receive the same event but with the action {@link MotionEvent#ACTION_CANCEL}, and all further events will be delivered to your onTouchEvent() method and no longer appear here.</span>
       如果返回false,后续事件还会传递到该方法中,经再次判断该方法返回值后,才会传递到子View中。 
       如果返回true,该方法不会接收到任何后续事件,所有的后继事件会直接传递到本View的onTouchEvent()中.但此时target view的事件接收分为两种情况:如果target view从来没有接收到该事件,那么仍旧不会接收到任何事件;如果target view曾经接收到过该事件,那么还会再一次,且仅一次地接收到该事件,只不过action为action_cancel。

OnTouchEvent():

       如果返回true,就不会执行父View的onTouchEvent()方法,代表着本次touch事件子View进行处理,父View不需要插手。
       如果返回false,在执行完子View的onTouchEvent()方法后还会执行父View的onTouchEvent()方法,此时事件是从子View往父View传递。返回false时,touch的后继事件不会传递到View的onTouchEvent()和onInterceptTouchEvent()中,即使父View的onInterceptTouchEvent()仍旧返回的是false,这个touch事件已经与子View没有任何关系了。

onTouch与onIntercept的返回值的四种情况

        (1)、onTouchEvent()返回false,onInterceptTouchEvent()返回true
        后续事件不会传递到子View、onIntercept与onTouch中.因为intercept返回true后,方法不会传递到子View以及intercept中;而touch又返回false,所以事件也不会传递到onTouch中。
(2)、onTouchEvent()返回true,onInterceptTouchEvent()返回true:
       后续事件不会传递到子View和onInterceptTouchEvent中,只会传递到onTouchEvent()中。
(3)、onTouchEvent()返回false,onInterceptTouchEvent()返回false:
       后续事件会走到intercept方法与子View中。但是不会走到本View的onTouchEvent中。
(4)、onTouchEvent()返回true,onInterceptTouchEvent()返回false:
       后续事件会走到intercept方法与子View中。但是不会走到本View的onTouchEvent中。

View#dispatchTouchEvent():

它在View.java中的源码为:

 public boolean dispatchTouchEvent(MotionEvent event) {        if (!onFilterTouchEventForSecurity(event)) {            return false;        }        if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&                mOnTouchListener.onTouch(this, event)) {            return true;        }        return onTouchEvent(event);    }

       从上面可以看出,setOnTouchEventListener()要优先于onTouchEvent()执行。而且touchListener如果返回为true的话,就不会再执行onTouchEvent()了

      并且该方法的主要作用是:把事件分发到onTouchEventListener和onTouchEvent()中。并不是用来决定事件要不要分发到子View中。

onLongClick,onClick与onTouch():

在View.java(安卓版本为2.2)文件中,它的onTouchEvent()代码片段为:

case MotionEvent.ACTION_DOWN:                    if (mPendingCheckForTap == null) {                        mPendingCheckForTap = new CheckForTap();                    }                    mPrivateFlags |= PREPRESSED;                    mHasPerformedLongPress = false;                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());                    break;
其中最后一句代码会延迟执行CheckForTap(),它的源码是:
 private final class CheckForTap implements Runnable {        public void run() {            mPrivateFlags &= ~PREPRESSED;            mPrivateFlags |= PRESSED;            refreshDrawableState();            if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {                postCheckForLongClick(ViewConfiguration.getTapTimeout());            }        }    }
而postCheckForLongClick()的源代码为:
 private void postCheckForLongClick(int delayOffset) {        mHasPerformedLongPress = false;        if (mPendingCheckForLongPress == null) {            mPendingCheckForLongPress = new CheckForLongPress();        }        mPendingCheckForLongPress.rememberWindowAttachCount();        postDelayed(mPendingCheckForLongPress,                ViewConfiguration.getLongPressTimeout() - delayOffset);    }
而CheckForLongPress的run()方法中又会调用到performLongClick(),其片段为:
 if (performLongClick()) {                    mHasPerformedLongPress = true;                }
而performLongClick()的源码为
 public boolean performLongClick() {        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);        boolean handled = false;        if (mOnLongClickListener != null) {            handled = mOnLongClickListener.onLongClick(View.this);        }        if (!handled) {            handled = showContextMenu();        }        if (handled) {            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);        }        return handled;    }
这里终于调用了onLongClick()方法。

       从上面可以看出:在ACTION_DOWN的时候,已经受理了onLongClick,只不过是延迟处理。

再看onTouchEvent()中的ACTION_UP

if (!mHasPerformedLongPress) {                            // 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();                                }                            }                        }
       其中会调用到performClick(),它里面就会调用onClick()。因此,onClick只是在ACTION_UP事件之后才会触发。同时,它有一个前提条件:mHasPerformedLongPress为false。如果mHasPerformedLongPress为true,就不会发生onClick事件。我们可以发现在整个View.java中,只有performLongClick()返回true时,mHasPerformedLongPress才会被赋值为true。同时,通过performLongClick()的源码,可以知道,performLongClick()的返回值就是onLongClick()的返回值。因此,当onLongClick返回true时,就不会执行onClick();如果返回false,就会执行

        longClick是从down事件开始的,click是up事件中执行的。因此,如果接收不到up事件,不会执行click事件。longClick返回true,也不会执行click事件;反之则会执行

click与longclick对onTouchEvent()返回值的要求

       由于click事件是ACTION_UP时才触发的,所以action_up之前onTouchEvent()必须返回true,但action_up时可以返回false。

       而longclick是在action_down中受理并延迟执行的,所以它对onTouchEvent()的返回值没有要求。只不过在action_up,action_cancel和action_move(move时移出view范围)时会取消对longclick的执行。因此,如果在down时如果返回false,那么longclick肯定会执行。

MotionEvent

        处理触摸事件时,经常需要重写onTouchEvent(),而传入该方法中的参数就代表着本次事件。并且可以支持多指触摸与单指触摸。

常用常量

        这些常量表示着当前事件的类型。

        ACTION_DOWN:第一根手指触摸发生down事件时。
        ACTION_POINTER_DOWN:非第一根手指发生down事件时。
        ACTION_UP:最后一根手指发生抬起时。
        ACTION_POINTER_UP:非最后一根手指抬起时。
        ACTION_MOVE:无论哪根手指移动,都会走该case。

常用方法

        getActioniMasked():获取当前事件类型。处理多指触摸获取事件类型时,必须使用该方法,否则返回的类型不会有ACTION_POINTER_DOWN。简单一句话:判断事件类型用getActionMasked()而不是getAction()

        getPointerCount():获取当前触摸的手指数。从0到getPointerCount()-1的值就是pointerIndex。getX,getY()等函数也可传入pointerIndex,用于获取指定手指的x,y坐标。
        getPointerId():根据pointerIndex获取pointerId。
        findPointerIndex():根据pointerId获取pointerIndex。
        getActionIndex():获取当前触发事件的手指的pointerIndex。

参考

可以参考stackoverflow。

        一般来说,多指触摸时,首先根据getActionIndex()得到当前事件手指的pointerIndex,再得到pointerId,最后在使用时由id得到index






0 0
原创粉丝点击