Android-onInterceptTouchEvent()和onTouchEvent()

来源:互联网 发布:游戏本品牌 知乎 编辑:程序博客网 时间:2024/05/17 23:24



1. WindowInputEventReceiver.onInputEvent()    ----ViewRootImpl.java

   从InputDispatch中publish一个Eent事件后,会由WindowInputEventReceiver.onInputEvent作为回调函数被调用。

[java] view plaincopy
  1. @Override  
  2. public void onInputEvent(InputEvent event) {  
  3.     enqueueInputEvent(event, this0true);  
  4. }  


1.2.   ViewRootImpl.enqueueInputEvent()

    把event作为一个QueuedInputEvent放到列表队列最后,如果processImmediately == true那么就直接执行doProcessInputEvents()去立即处理这个event事件,如果不是就调用scheduleProcessInputEvents把Eent通过hander放入到主线程的Looper中。

[java] view plaincopy
  1. void enqueueInputEvent(InputEvent event,  
  2.         InputEventReceiver receiver, int flags, boolean processImmediately) {  
  3.     QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);  
  4.   
  5.     // Always enqueue the input event in order, regardless of its time stamp.  
  6.     // We do this because the application or the IME may inject key events  
  7.     // in response to touch events and we want to ensure that the injected keys  
  8.     // are processed in the order they were received and we cannot trust that  
  9.     // the time stamp of injected events are monotonic.  
  10.     QueuedInputEvent last = mFirstPendingInputEvent;  
  11.     if (last == null) {  
  12.         mFirstPendingInputEvent = q;  
  13.     } else {  
  14.         while (last.mNext != null) {  
  15.             last = last.mNext;  
  16.         }  
  17.         last.mNext = q;  
  18.     }  
  19.   
  20.     if (processImmediately) {  
  21.         doProcessInputEvents();  
  22.     } else {  
  23.         scheduleProcessInputEvents();  
  24.     }  
  25. }  

2.  ViewRootImpl.deliverInputEvent()

     最后都会调用deliverInputEvent去分发事件,如果是KeyEent就调用deliverKeyEent(),同理如果是Touch,Pointer Event就调用deliverPointerEvent。

[java] view plaincopy
  1. private void deliverInputEvent(QueuedInputEvent q) {  
  2.     Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");  
  3.     try {  
  4.         if (q.mEvent instanceof KeyEvent) {  
  5.             deliverKeyEvent(q);  
  6.         } else {  
  7.             final int source = q.mEvent.getSource();  
  8.             if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {  
  9.                 deliverPointerEvent(q);  
  10.             } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {  
  11.                 deliverTrackballEvent(q);  
  12.             } else {  
  13.                 deliverGenericMotionEvent(q);  
  14.             }  
  15.         }  
  16.     } finally {  
  17.         Trace.traceEnd(Trace.TRACE_TAG_VIEW);  
  18.     }  
  19. }  

2.1  ViewRootImpl.deliverPointerEvent()

    1. 如果mView == null || !mAdded, 就直接调用fininshInputEvent去告诉InputDispatcher;

    2. 如果是ActionDown就是通过ensureTouchMode(true)告诉WMS去设置对应WindowState的touch mode,并且调用ensureTouchModeLocally来handle the change

    3. 如果是touchevent就是用mLastTouchPoint去记录此次的Point的Position用于possible drag-initiation

    4. mView.dispatchPointerEvent(event);  通过DecorView去dispatchPointerEvent;

    5. 无论Event是否被处理,都会调用finishInputEvent(q, true);去告诉InputDispatcher。

[java] view plaincopy
  1. private void deliverPointerEvent(QueuedInputEvent q) {  
  2.     final MotionEvent event = (MotionEvent)q.mEvent;  
  3.     final boolean isTouchEvent = event.isTouchEvent();  
  4.     if (mInputEventConsistencyVerifier != null) {  
  5.         if (isTouchEvent) {  
  6.             mInputEventConsistencyVerifier.onTouchEvent(event, 0);  
  7.         } else {  
  8.             mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);  
  9.         }  
  10.     }  
  11.   
  12.     // If there is no view, then the event will not be handled.  
  13.     if (mView == null || !mAdded) {  
  14.         finishInputEvent(q, false);  
  15.         return;  
  16.     }  
  17.   
  18.     // Translate the pointer event for compatibility, if needed.  
  19.     if (mTranslator != null) {  
  20.         mTranslator.translateEventInScreenToAppWindow(event);  
  21.     }  
  22.   
  23.     // Enter touch mode on down or scroll.  
  24.     final int action = event.getAction();  
  25.     if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {  
  26.         ensureTouchMode(true);  
  27.     }  
  28.   
  29.     // Offset the scroll position.  
  30.     if (mCurScrollY != 0) {  
  31.         event.offsetLocation(0, mCurScrollY);  
  32.     }  
  33.     if (MEASURE_LATENCY) {  
  34.         lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());  
  35.     }  
  36.   
  37.     // Remember the touch position for possible drag-initiation.  
  38.     if (isTouchEvent) {  
  39.         mLastTouchPoint.x = event.getRawX();  
  40.         mLastTouchPoint.y = event.getRawY();  
  41.     }  
  42.   
  43.     // Dispatch touch to view hierarchy.  
  44.     boolean handled = mView.dispatchPointerEvent(event);  
  45.     if (MEASURE_LATENCY) {  
  46.         lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());  
  47.     }  
  48.     if (handled) {  
  49.         finishInputEvent(q, true);  
  50.         return;  
  51.     }  
  52.   
  53.     // Pointer event was unhandled.  
  54.     finishInputEvent(q, false);  
  55. }  


2.1.4 DecorView.dispatchPointerEvent

     DecorView继承FrameLayout也就间接继承了ViewGroup,View。

    1. 调用父类View的dispatchPointerEvent(), 然后去调用自己的dispatchTouchEvent;

    2. dispatchTouchEvent中调用callback.dispatchTouchEvent,这里的Callback就是Activity对象。

[java] view plaincopy
  1. public final boolean dispatchPointerEvent(MotionEvent event) {  
  2.     if (event.isTouchEvent()) {  
  3.         return dispatchTouchEvent(event);  
  4.     } else {  
  5.         return dispatchGenericMotionEvent(event);  
  6.     }  
  7. }  

[java] view plaincopy
  1. @Override  
  2. public boolean dispatchTouchEvent(MotionEvent ev) {  
  3.     final Callback cb = getCallback();  
  4.     return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)  
  5.             : super.dispatchTouchEvent(ev);  
  6. }  

2.1.4.2 Activity.dispatchtouchEvent

       1. onUserInteraction(), 在dispatch之前做一些操作

       2. getwindow().superDispatchtouchEvent就是调用PhoneWindow中的superDispatchTouchEvent。而PhoneWindow也是直接调用mDecorView的对应的方法。而DoverView的superDispatchTouchEvent方法中是去调用了父类ViewGroup的dispatchTouchEvent。

       3. 当Activity中所有的View都不处理Event的时候,就用由Activity的onTouchEvent()来处理。

        这里的调用顺序从DoverView---->Activity-->PhoneWindow--->DocerView---->ViewGroup

[java] view plaincopy
  1. public boolean dispatchTouchEvent(MotionEvent ev) {  
  2.     if (ev.getAction() == MotionEvent.ACTION_DOWN) {  
  3.         onUserInteraction();  
  4.     }  
  5.     if (getWindow().superDispatchTouchEvent(ev)) {  
  6.         return true;  
  7.     }  
  8.     return onTouchEvent(ev);  
  9. }  

2.1.4.2.1 ViewGroupdispatchTouchEvent(MotionEvent ev) 

     1. 如果是Action_Down事件,那么把之前的TouchTargets和TouchState都clear掉,mFirstTouchTarget = null

     2. onInterceptTouchEvent(),通过这个函数去告诉当前的View是否拦截掉这个Event,如果return就不会把这个event往下dispatch了

     3. 如果不去Intercept当前的Event,就通过遍历自己的child views去找到处在Touch所在区域的view,找到之后通过getTouchTarget(View)去查找View是否在TouchTarget中了;如果不在,则调用dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign),把Event分发给child view。

     4. 如果child没有消耗掉event事件,那么mFirstTouchTarget == null),这时候就会调用handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS)自己去处理此次Event; 参数中child为null。

        如果ViewGroup也没处理,就会以此回溯上去给父View处理。


[java] view plaincopy
  1. public boolean dispatchTouchEvent(MotionEvent ev) {  
  2.     if (mInputEventConsistencyVerifier != null) {  
  3.         mInputEventConsistencyVerifier.onTouchEvent(ev, 1);  
  4.     }  
  5.   
  6.     boolean handled = false;  
  7.     if (onFilterTouchEventForSecurity(ev)) {  
  8.         final int action = ev.getAction();  
  9.         final int actionMasked = action & MotionEvent.ACTION_MASK;  
  10.   
  11.         // Handle an initial down.  
  12.         if (actionMasked == MotionEvent.ACTION_DOWN) {  
  13.             // Throw away all previous state when starting a new touch gesture.  
  14.             // The framework may have dropped the up or cancel event for the previous gesture  
  15.             // due to an app switch, ANR, or some other state change.  
  16.             cancelAndClearTouchTargets(ev);  
  17.             resetTouchState();  
  18.         }  
  19.   
  20.         // Check for interception.  
  21.         final boolean intercepted;  
  22.         if (actionMasked == MotionEvent.ACTION_DOWN  
  23.                 || mFirstTouchTarget != null) {  
  24.             final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  
  25.             if (!disallowIntercept) {  
  26.                 intercepted = onInterceptTouchEvent(ev);  
  27.                 ev.setAction(action); // restore action in case it was changed  
  28.             } else {  
  29.                 intercepted = false;  
  30.             }  
  31.         } else {  
  32.             ... ...  
  33.         }  
  34.   
  35.         // Check for cancelation.  
  36.         final boolean canceled = resetCancelNextUpFlag(this)  
  37.                 || actionMasked == MotionEvent.ACTION_CANCEL;  
  38.   
  39.         // Update list of touch targets for pointer down, if needed.  
  40.         final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;  
  41.         TouchTarget newTouchTarget = null;  
  42.         boolean alreadyDispatchedToNewTouchTarget = false;  
  43.         if (!canceled && !intercepted) {  
  44.             if (actionMasked == MotionEvent.ACTION_DOWN  
  45.                     || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)  
  46.                     || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {  
  47.                 final int actionIndex = ev.getActionIndex(); // always 0 for down  
  48.                 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)  
  49.                         : TouchTarget.ALL_POINTER_IDS;  
  50.   
  51.                 // Clean up earlier touch targets for this pointer id in case they  
  52.                 // have become out of sync.  
  53.                 removePointersFromTouchTargets(idBitsToAssign);  
  54.   
  55.                 final int childrenCount = mChildrenCount;  
  56.                 if (childrenCount != 0) {  
  57.                     // Find a child that can receive the event.  
  58.                     // Scan children from front to back.  
  59.                     final View[] children = mChildren;  
  60.                     final float x = ev.getX(actionIndex);  
  61.                     final float y = ev.getY(actionIndex);  
  62.   
  63.                     for (int i = childrenCount - 1; i >= 0; i--) {  
  64.                         final View child = children[i];  
  65.                         if (!canViewReceivePointerEvents(child)  
  66.                                 || !isTransformedTouchPointInView(x, y, child, null)) {  
  67.                             continue;  
  68.                         }  
  69.   
  70.                         newTouchTarget = getTouchTarget(child);  //通过getTouchTarget去查找View是否在TouchTarget中了。  
  71.                         if (newTouchTarget != null) {  
  72.                             // Child is already receiving touch within its bounds.  
  73.                             // Give it the new pointer in addition to the ones it is handling.  
  74.                             newTouchTarget.pointerIdBits |= idBitsToAssign;  
  75.                             break;  
  76.                         }  
  77.   
  78.                         resetCancelNextUpFlag(child);  
  79.                         if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {  
  80.                             // Child wants to receive touch within its bounds.  
  81.                             mLastTouchDownTime = ev.getDownTime();  
  82.                             mLastTouchDownIndex = i;  
  83.                             mLastTouchDownX = ev.getX();  
  84.                             mLastTouchDownY = ev.getY();  
  85.                             newTouchTarget = addTouchTarget(child, idBitsToAssign);  
  86.                             alreadyDispatchedToNewTouchTarget = true;  
  87.                             break;  
  88.                         }  
  89.                     }  
  90.                 }  
  91.   
  92.                 if (newTouchTarget == null && mFirstTouchTarget != null) {  
  93.                     // Did not find a child to receive the event.  
  94.                     // Assign the pointer to the least recently added target.  
  95.                     newTouchTarget = mFirstTouchTarget;  
  96.                     while (newTouchTarget.next != null) {  
  97.                         newTouchTarget = newTouchTarget.next;  
  98.                     }  
  99.                     newTouchTarget.pointerIdBits |= idBitsToAssign;  
  100.                 }  
  101.             }  
  102.         }  
  103.   
  104.         // Dispatch to touch targets.  
  105.         if (mFirstTouchTarget == null) {  
  106.             // No touch targets so treat this as an ordinary view.  
  107.             handled = dispatchTransformedTouchEvent(ev, canceled, null,  
  108.                     TouchTarget.ALL_POINTER_IDS);  
  109.         } else {  
  110.             // Dispatch to touch targets, excluding the new touch target if we already  
  111.             // dispatched to it.  Cancel touch targets if necessary.  
  112.             TouchTarget predecessor = null;  
  113.             TouchTarget target = mFirstTouchTarget;  
  114.             while (target != null) {  
  115.                 final TouchTarget next = target.next;  
  116.                 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {  
  117.                     handled = true;  
  118.                 } else {  
  119.                     final boolean cancelChild = resetCancelNextUpFlag(target.child)  
  120.                     || intercepted;  
  121.                     if (dispatchTransformedTouchEvent(ev, cancelChild,  
  122.                             target.child, target.pointerIdBits)) {  
  123.                         handled = true;  
  124.                     }  
  125.                     if (cancelChild) {  
  126.                         if (predecessor == null) {  
  127.                             mFirstTouchTarget = next;  
  128.                         } else {  
  129.                             predecessor.next = next;  
  130.                         }  
  131.                         target.recycle();  
  132.                         target = next;  
  133.                         continue;  
  134.                     }  
  135.                 }  
  136.                 predecessor = target;  
  137.                 target = next;  
  138.             }  
  139.         }  
  140.   
  141.         // Update list of touch targets for pointer up or cancel, if needed.  
  142.         if (canceled  
  143.                 || actionMasked == MotionEvent.ACTION_UP  
  144.                 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {  
  145.             resetTouchState();  
  146.         } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {  
  147.             final int actionIndex = ev.getActionIndex();  
  148.             final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);  
  149.             removePointersFromTouchTargets(idBitsToRemove);  
  150.         }  
  151.     }  
  152.   
  153.     if (!handled && mInputEventConsistencyVerifier != null) {  
  154.         mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);  
  155.     }  
  156.     return handled;  
  157. }  


2.1.4.2.1.3 ViewGroup.dispatchTransformedTouchEvent()

     1. 主要是调用child.dispatchTouchEvent(transformedEvent);把事件递归传下去,如果child还是一个ViewGroup那么步骤和上面有一样,如果是View就调用View.dispatchTouchEvent(MotionEvent event)

[java] view plaincopy
  1. private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,  
  2.           View child, int desiredPointerIdBits) {  
  3.       final boolean handled;  
  4.   
  5.        // Calculate the number of pointers to deliver.  
  6.       final int oldPointerIdBits = event.getPointerIdBits();  
  7.       final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;  
  8.   
  9.       // If the number of pointers is the same and we don't need to perform any fancy  
  10.       // irreversible transformations, then we can reuse the motion event for this  
  11.       // dispatch as long as we are careful to revert any changes we make.  
  12.       // Otherwise we need to make a copy.  
  13.       final MotionEvent transformedEvent;  
  14.       if (newPointerIdBits == oldPointerIdBits) {  
  15.           if (child == null || child.hasIdentityMatrix()) {  
  16.               if (child == null) {  
  17.                   handled = super.dispatchTouchEvent(event);  
  18.               } else {  
  19.                   final float offsetX = mScrollX - child.mLeft;  
  20.                   final float offsetY = mScrollY - child.mTop;  
  21.                   event.offsetLocation(offsetX, offsetY);  
  22.   
  23.                   handled = child.dispatchTouchEvent(event);  
  24.   
  25.                   event.offsetLocation(-offsetX, -offsetY);  
  26.               }  
  27.               return handled;  
  28.           }  
  29.           transformedEvent = MotionEvent.obtain(event);  
  30.       } else {  
  31.           transformedEvent = event.split(newPointerIdBits);  
  32.       }  
  33.   
  34.       // Perform any necessary transformations and dispatch.  
  35.       if (child == null) {  
  36.           handled = super.dispatchTouchEvent(transformedEvent);  
  37.       } else {  
  38.           final float offsetX = mScrollX - child.mLeft;  
  39.           final float offsetY = mScrollY - child.mTop;  
  40.           transformedEvent.offsetLocation(offsetX, offsetY);  
  41.           if (! child.hasIdentityMatrix()) {  
  42.               transformedEvent.transform(child.getInverseMatrix());  
  43.           }  
  44.   
  45.           handled = child.dispatchTouchEvent(transformedEvent);  
  46.       }  
  47.   
  48.       // Done.  
  49.       transformedEvent.recycle();  
  50.       return handled;  
  51.   }  

2.1.4.2.1.3.1View.dispatchTouchEvent(MotionEvent event)

     1. 如果有TouchListener就去调用注册过的TouchListener的回调函数onTouch事件并直接返回。这就是为什么我们想接收一个touch event的时候只要写一个listener的原故。

     2. 如果没有TouchListener,则调用默认的onTouchEvent(event)事件

[java] view plaincopy
  1. public boolean dispatchTouchEvent(MotionEvent event) {  
  2.     if (mInputEventConsistencyVerifier != null) {  
  3.         mInputEventConsistencyVerifier.onTouchEvent(event, 0);  
  4.     }  
  5.   
  6.     if (onFilterTouchEventForSecurity(event)) {  
  7.         //noinspection SimplifiableIfStatement  
  8.         ListenerInfo li = mListenerInfo;  
  9.         if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED  
  10.                 && li.mOnTouchListener.onTouch(this, event)) {  
  11.             return true;  
  12.         }  
  13.   
  14.         if (onTouchEvent(event)) {  
  15.             return true;  
  16.         }  
  17.     }  
  18.   
  19.     if (mInputEventConsistencyVerifier != null) {  
  20.         mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);  
  21.     }  
  22.     return false;  
  23. }  

2.1.4.2.1.4 Activity.onTouchEvent(MotionEvent event)

  如果所有的View都不处理TouchEvent,最后由Activity来处理。

  判断一下mWindow是否因此此Event要close掉,如果不close,就return false。

 最后调用FinishInputEvent(false), 返回这个没有处理的Event。

[java] view plaincopy
  1. public boolean onTouchEvent(MotionEvent event) {  
  2.     if (mWindow.shouldCloseOnTouch(this, event)) {  
  3.         finish();  
  4.         return true;  
  5.     }  
  6.       
  7.     return false;  
  8. }  




------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



老实说,这两个小东东实在是太麻烦了,很不好懂,我自己那api文档都头晕,在网上找到很多资料,才知道是怎么回事,这里总结一下,记住这个原则就会很清楚了:

1、onInterceptTouchEvent()是用于处理事件(类似于预处理,当然也可以不处理)并改变事件的传递方向,也就是决定是否允许Touch事件继续向下(子控件)传递,一但返回True(代表事件在当前的viewGroup中会被处理),则向下传递之路被截断(所有子控件将没有机会参与Touch事件),同时把事件传递给当前的控件的onTouchEvent()处理;返回false,则把事件交给子控件的onInterceptTouchEvent()


2、onTouchEvent()用于处理事件,返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递,一但返回True,则父控件不用操心自己来处理Touch事件。返回true,则向上传递给父控件(注:可能你会觉得是否消费了有关系吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。)



概念介绍

1、onInterceptTouchEvent()是用于处理事件(重点onInterceptTouchEvent这个事件是从父控件开始往子控件传的,直到有拦截或者到没有这个事件的view,然后就往回从子到父控件,这次是onTouch的)(类似于预处理,当然也可以不处理)并改变事件的传递方向,也就是决定是否允许Touch事件继续向下(子控件)传递,一但返回True(代表事件在当前的viewGroup中会被处理),则向下传递之路被截断(所有子控件将没有机会参与Touch事件),同时把事件传递给当前的控件的onTouchEvent()处理;返回false,则把事件交给子控件的onInterceptTouchEvent()

 

2、onTouchEvent()用于处理事件(重点onTouch这个事件是从子控件回传到父控件的,一层层向下传),返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递。返回false,则向上传递给父控件,详细一点就是这个touch事件就给了父控件,那么后面的up事件就是到这里touch触发,不会在传给它的子控件。如果父控件依然是false,那touch的处理就给到父控件的父控件,那么up的事件处理都在父控件的父控件,不会触发下面的。

返回true,如果是子控件返回true,那么它的touch事件都在这里处理,父控件是处理不了,因为它收不到子控件传给他的touch,被子控件给拦截了。(这里啰嗦了这么多就是为了加深记忆,这个两个事件理解起来都这么麻烦了,更何况去记,记我肯定是一下子就忘的了^0^)

(注:可能你会觉得是否消费了有关系吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。)

详细介绍

onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,Android这么设计的想法也很好理解,由于ViewGroup会包含若干childView,因此需要能够统一监控各种touch事件的机会,因此纯粹的不能包含子view的控件是没有这个方法的,如LinearLayout就有,TextView就没有。

onInterceptTouchEvent()使用也很简单,如果在ViewGroup里覆写了该方法,那么就可以对各种touch事件加以拦截。但是如何拦截,是否所有的touch事件都需要拦截则是比较复杂的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各个childView间的传递机制完全取决于onInterceptTouchEvent()和onTouchEvent()的返回值。并且,针对down事件处理的返回值直接影响到后续move和up事件的接收和传递。

关于返回值的问题,基本规则很清楚,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。


onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截.

  1. down事件首先会传递到onInterceptTouchEvent()方法

  2. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。

  3. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

  4. 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。

  5. 如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。


    仅仅看这个官方文档解释,就能理解清楚这两个函数关系以及用途的绝对是富有经验的framework高手。
    否则,一定需要一个案例来阐释。假设我们有这样一个layout,非常典型的

    <ol class="linenums" style="list-style-position: outside; margin: 0px; padding: 0px 0px 0px 10px; border: none;"><li class="L0" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="tag" style="color: maroon; font-weight: bold;"><com.test.LayoutView1</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="atn" style="color: red;">xmlns:android</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"http://schemas.android.com/apk/res/android"</span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L1" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">    </span><span class="atn" style="color: red;">android:orientation</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"vertical"</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="atn" style="color: red;">android:layout_width</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"fill_parent"</span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L2" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">    </span><span class="atn" style="color: red;">android:layout_height</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"fill_parent"</span><span class="tag" style="color: maroon; font-weight: bold;">></span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L3" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">    </span><span class="tag" style="color: maroon; font-weight: bold;"><com.test.LayoutView2</span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L4" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="atn" style="color: red;">android:orientation</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"vertical"</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="atn" style="color: red;">android:layout_width</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"fill_parent"</span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L5" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="atn" style="color: red;">android:layout_height</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"fill_parent"</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="atn" style="color: red;">android:gravity</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"center"</span><span class="tag" style="color: maroon; font-weight: bold;">></span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L6" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="tag" style="color: maroon; font-weight: bold;"><com.test.MyTextView</span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L7" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">            </span><span class="atn" style="color: red;">android:layout_width</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"wrap_content"</span><span class="pln" style="color: rgb(0, 0, 0);">   </span><span class="atn" style="color: red;">android:layout_height</span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="atv" style="color: blue;">"wrap_content"</span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L8" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">      </span><span class="tag" style="color: maroon; font-weight: bold;">/></span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L9" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">    </span><span class="tag" style="color: maroon; font-weight: bold;"></com.test.LayoutView2></span><span class="pln" style="color: rgb(0, 0, 0);">  </span></li><li class="L0" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);"></span><span class="tag" style="color: maroon; font-weight: bold;"></com.test.LayoutView1></span></li></ol>

    用一个示例图来解释这个layout:


    通常外围的layoutview1,layoutview2,只是布局的容器不需要响应触屏的点击事件,仅仅Mytextview需要相应点击。但这只是一般情况,一些特殊的布局可能外围容器也要响应,甚至不让里面的mytextview去响应。更有特殊的情况是,动态更换响应对象。
    那么首先看一下默认的触屏事件的在两个函数之间的传递流程。如下图:


    如果仅仅想让MyTextView来响应触屏事件,让MyTextView的OnTouchEvent返回true,那么事件流就变成如下图,可以看到layoutview1,layoutview2已经不能进入OnTouchEvent:


    另外一种情况,就是外围容器想独自处理触屏事件,那么就应该在相应的onInterceptTouchEvent函数中返回true,表示要截获触屏事件,比如layoutview1作截获处理,处理流变成如下图:


    以此类推,我们可以得到各种具体的情况,整个layout的view类层次中都有机会截获,而且能看出来外围的容器view具有优先截获权。

    当我们去做一些相对来讲具有更复杂的触屏交互效果的应用时候,经常需要动态变更touch event的处理对象,比如launcher待机桌面和主菜单(见下图),从滑动屏幕开始到停止滑动过程当中,只有外围的容器view才可以处理touch event,否则就会误点击上面的应用图标或者widget.反之在静止不动的状态下则需要能够响应图标(子view)的touch事件。摘取framework中abslistview代码如下

    <ol class="linenums" style="list-style-position: outside; margin: 0px; padding: 0px 0px 0px 10px; border: none;"><li class="L0" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">boolean</span><span class="pln" style="color: rgb(0, 0, 0);"> onInterceptTouchEvent</span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="typ" style="color: rgb(43, 145, 175); font-weight: bold;">MotionEvent</span><span class="pln" style="color: rgb(0, 0, 0);"> ev</span><span class="pun" style="color: rgb(0, 0, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L1" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">int</span><span class="pln" style="color: rgb(0, 0, 0);"> action </span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> ev</span><span class="pun" style="color: rgb(0, 0, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getAction</span><span class="pun" style="color: rgb(0, 0, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L2" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L3" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">switch</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">action </span><span class="pun" style="color: rgb(0, 0, 0);">&</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(43, 145, 175); font-weight: bold;">MotionEvent</span><span class="pun" style="color: rgb(0, 0, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">ACTION_MASK</span><span class="pun" style="color: rgb(0, 0, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L4" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">case</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(43, 145, 175); font-weight: bold;">MotionEvent</span><span class="pun" style="color: rgb(0, 0, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">ACTION_DOWN</span><span class="pun" style="color: rgb(0, 0, 0);">:</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L5" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);"> </span></li><li class="L6" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">            </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">if</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">touchMode </span><span class="pun" style="color: rgb(0, 0, 0);">==</span><span class="pln" style="color: rgb(0, 0, 0);"> TOUCH_MODE_FLING</span><span class="pun" style="color: rgb(0, 0, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L7" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">                </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">true</span><span class="pun" style="color: rgb(0, 0, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">  </span><span class="com" style="color: gray;">//fling状态,截获touch,因为在滑动状态,不让子view处理</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L8" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">            </span><span class="pun" style="color: rgb(0, 0, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L9" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">            </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">break</span><span class="pun" style="color: rgb(0, 0, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L0" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="pun" style="color: rgb(0, 0, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L1" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L2" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">case</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(43, 145, 175); font-weight: bold;">MotionEvent</span><span class="pun" style="color: rgb(0, 0, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">ACTION_MOVE</span><span class="pun" style="color: rgb(0, 0, 0);">:</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L3" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">            </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">switch</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">mTouchMode</span><span class="pun" style="color: rgb(0, 0, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L4" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">            </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">case</span><span class="pln" style="color: rgb(0, 0, 0);"> TOUCH_MODE_DOWN</span><span class="pun" style="color: rgb(0, 0, 0);">:</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L5" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">                </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">int</span><span class="pln" style="color: rgb(0, 0, 0);"> pointerIndex </span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> ev</span><span class="pun" style="color: rgb(0, 0, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">findPointerIndex</span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">mActivePointerId</span><span class="pun" style="color: rgb(0, 0, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L6" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">                </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">int</span><span class="pln" style="color: rgb(0, 0, 0);"> y </span><span class="pun" style="color: rgb(0, 0, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">int</span><span class="pun" style="color: rgb(0, 0, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> ev</span><span class="pun" style="color: rgb(0, 0, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getY</span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">pointerIndex</span><span class="pun" style="color: rgb(0, 0, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L7" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">                </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">if</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">startScrollIfNeeded</span><span class="pun" style="color: rgb(0, 0, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">y </span><span class="pun" style="color: rgb(0, 0, 0);">-</span><span class="pln" style="color: rgb(0, 0, 0);"> mMotionY</span><span class="pun" style="color: rgb(0, 0, 0);">))</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(0, 0, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L8" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">                    </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">true</span><span class="pun" style="color: rgb(0, 0, 0);">;</span><span class="com" style="color: gray;">//开始滑动状态,截获touch事件,不让子view处理</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L9" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">                </span><span class="pun" style="color: rgb(0, 0, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L0" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">                </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">break</span><span class="pun" style="color: rgb(0, 0, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L1" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">            </span><span class="pun" style="color: rgb(0, 0, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L2" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">            </span><span class="kwd" style="color: rgb(0, 0, 139); font-weight: bold;">break</span><span class="pun" style="color: rgb(0, 0, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L3" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="pun" style="color: rgb(0, 0, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);"></span></li><li class="L4" style="list-style: decimal; margin: 0px; padding: 0px 0px 0px 10px; border: none; line-height: 20px; color: rgb(153, 153, 153); background-color: rgb(250, 250, 250);"><span class="pln" style="color: rgb(0, 0, 0);"></span><span class="pun" style="color: rgb(0, 0, 0);">}</span></li></ol>



    总结:

    仅仅通过概览性的官方文档是很难理解onInterceptTouchEvent函数的用途的,只有通过演绎这个抽象的规则,配以图文才能获取这个重要的知识。很显然,默认是返回false,不做截获。返回true之后,事件流的后端控件就没有机会处理touch事件了,把默认的事件流中每个处理函数看作一个节点,这个节点只要返回true, 后续的事件就被截止了,这样想就很好理解。




    onInterceptTouchEvent是在ViewGroup里面定义的。Android中的layout布局类一般都是继承此类的。onInterceptTouchEvent是用于拦截手势事件的,每个手势事件都会先调用onInterceptTouchEvent。 
    onInterceptTouchEvent()用于处理事件并改变事件的传递方向。返回值为false时事件会传递给子控件的onInterceptTouchEvent();返回值为true时事件会传递给当前控件的onTouchEvent(),而不在传递给子控件,这就是所谓的Intercept(截断)。
    onTouchEvent() 用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。可能你要问是否消费了又区别吗,反正我已经针对事件编写了处理代码?答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。


ViewGroup里的onInterceptTouchEvent默认值是false这样才能把事件传给View里的onTouchEvent.

ViewGroup里的onTouchEvent默认值是false。

View里的onTouchEvent返回默认值是true.这样才能执行多次touch事件。



0 0
原创粉丝点击