onInterceptTouchEvent 与 onTouchEvent 分析与MotionEvent在ViewGroup与View中的分发

来源:互联网 发布:unity3d 室内场景资源 编辑:程序博客网 时间:2024/06/16 08:22

onInterceptTouchEvent 与 onTouchEvent 分析与MotionEvent在ViewGroup与View中的分发

       Notice:本文将紧接着
Android 触屏事件 OnTouch onClick onTouchEvent对于触屏事件的处理和分发
这一片博文来分析,如果您还没有读过这一片博文,强烈建议你先读一次上述博文


     OK,言归正传,我们开始吧
      最近,一直听到有人在争论关于dispatchTouchEvent这个函数 和 onInterceptTouchEvent这两个函数到底是那一这真正的决定了MotionEvent的分发。这里我还是统一给出答案吧。我们都知道如果我们不希望我们的ViewGroup阻拦我们的View获得MotionEvent,我们一般只需要在onInterceptTouchEvent这个函数中return false(并且该函数默认return false)。或者,在特定的情况下,如果我们希望某些时候交给我们的我们ViewGroup来处理有些情况下我们又希望我们的View来处理MotionEvent。这种情况下,我们应该怎么来处理呢。我想大家都知道,我们需要在onInterceptTouchEvent做一些处理,因为大家都知道onInterceptTouchEvent是用来做MotionEvent事件的处理对象判断的。

    那么,答案很明显了,处理MotionEvent只有dispatchTouchEvent(其实这一点从函数名称都可以看出来,更不要说onInterceptTouchEvent还只是ViewGroup特有的方法)。

    好,我们先来整理我们目前已知的,并且提出疑问然后再开始分析
 
    一、Android 中的MotionEvent事件分发处理是由dispatchTouchEvent来完成的(底层直接调用该方法,我们这里不分析)
  
    二、通过上一篇博文我们知道dispatchTouchEvent > onTouch > onTouchEvent > onClick
            这里我还是简单啰嗦一下吧,其实onTouchListener 和 onClickListener 只是为了提供给上层便捷的处理接口,他们的存在只是为了对于开发提供了便捷,但是在Android中我们通常采用onInterceptTouchEvent和onTouchEvent 联合来判断MotionEvent的处理对象

    三、我们在ViewGroup中采用onInterceptTouchEvent和onTouchEvent 联合来判断MotionEvent的处理对象


     OK,结论到此结束,我们应该提出问题。
      一、既然MotionEvent事件是由dispatchTouchEvent来分发的,那么他和onInterceptTouchEvent又是什么关系呢

        二、onInterceptTouchEvent和onTouchEvent 是怎样来完成事件分发的

    那么,到了现在,我们的主题只有一个,解决上面的两个问题即可。
     对于第一个问题,最好的解决方式,很明显我们需要靠源码来解决
     下面,我先给出ViewGroup重写之后的dispatchTouchEvent函数,这里我们需要注意的事他并没有调用super.dispatchTouchEvent。而是实实在在的重写了所有逻辑(至于View源码的dispatchTouchEvent,各位看官去我的上一篇博文里面去看看吧)
[java] view plaincopy
  1. @Override  
  2.     public boolean dispatchTouchEvent(MotionEvent ev) {  
  3.         if (mInputEventConsistencyVerifier != null) {  
  4.             mInputEventConsistencyVerifier.onTouchEvent(ev, 1);  
  5.         }  
  6.   
  7.         if (DBG_MOTION || DBG_TOUCH) {  
  8.             Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent 1: ev = " + ev + ",mFirstTouchTarget = "  
  9.                     + mFirstTouchTarget + ",this = " + this);  
  10.         }  
  11.   
  12.         boolean handled = false;  
  13.         if (onFilterTouchEventForSecurity(ev)) {  //上一篇博文中提到的遮蔽判断其实是错误的,这里指的应该是窗口被其他窗口遮挡,很明显一般情况下是不会的  
  14.             final int action = ev.getAction();  
  15.             final int actionMasked = action & MotionEvent.ACTION_MASK;  
  16.   
  17.             // Handle an initial down.  
  18.             if (actionMasked == MotionEvent.ACTION_DOWN) {  
  19.                 // Throw away all previous state when starting a new touch gesture.  
  20.                 // The framework may have dropped the up or cancel event for the previous gesture  
  21.                 // due to an app switch, ANR, or some other state change.  
  22.                 cancelAndClearTouchTargets(ev);  
  23.                 resetTouchState();  
  24.             }  
  25.   
  26.             // Check for interception.  
  27.             final boolean intercepted;  
  28.             if (actionMasked == MotionEvent.ACTION_DOWN  
  29.                     || mFirstTouchTarget != null) {  
  30.                 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  
  31.                 if (!disallowIntercept) {  
  32.                     intercepted = onInterceptTouchEvent(ev);//这里开始判断  
  33.                     /// M : add log to help debugging  
  34.                     if (intercepted == true) {  
  35.                         if (DBG_TOUCH) {  
  36.                             Xlog.d(TAG, "Touch event was intercepted event = " + ev + ",this = " + this);  
  37.                         }  
  38.                     }  
  39.                     ev.setAction(action); // restore action in case it was changed  
  40.                 } else {  
  41.                     intercepted = false;  
  42.                 }  
  43.             } else {  
  44.                 // There are no touch targets and this action is not an initial down  
  45.                 // so this view group continues to intercept touches.  
  46.                 intercepted = true;  
  47.             }  
  48.   
  49.             // Check for cancelation.  
  50.             final boolean canceled = resetCancelNextUpFlag(this)  
  51.                     || actionMasked == MotionEvent.ACTION_CANCEL;  
  52.   
  53.             // Update list of touch targets for pointer down, if needed.  
  54.             final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;  
  55.             if (DBG_MOTION) {  
  56.                 Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent 2: actionMasked = " + actionMasked  
  57.                         + ",intercepted = " + intercepted + ",canceled = " + canceled + ",split = "  
  58.                         + split + ",mChildrenCount = " + mChildrenCount + ",mFirstTouchTarget = "  
  59.                         + mFirstTouchTarget + ",this = " + this);  
  60.             }  
  61.   
  62.             TouchTarget newTouchTarget = null;  
  63.             boolean alreadyDispatchedToNewTouchTarget = false;  
  64. if (!canceled && !intercepted) {     //依据interceptd 分析转折点  
  65.                 if (actionMasked == MotionEvent.ACTION_DOWN  
  66.                         || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)  
  67.                         || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {  
  68.                     final int actionIndex = ev.getActionIndex(); // always 0 for down  
  69.                     final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)  
  70.                             : TouchTarget.ALL_POINTER_IDS;  
  71.   
  72.                     // Clean up earlier touch targets for this pointer id in case they  
  73.                     // have become out of sync.  
  74.                     removePointersFromTouchTargets(idBitsToAssign);  
  75.   
  76.                     final int childrenCount = mChildrenCount;  
  77.                     if (newTouchTarget == null && childrenCount != 0) {  
  78.                         final float x = ev.getX(actionIndex);  
  79.                         final float y = ev.getY(actionIndex);  
  80.                         // Find a child that can receive the event.  
  81.                         // Scan children from front to back.  
  82.                         final View[] children = mChildren;  
  83.   
  84.                         final boolean customOrder = isChildrenDrawingOrderEnabled();  
  85.                         for (int i = childrenCount - 1; i >= 0; i--) {  
  86.                             final int childIndex = customOrder ?  
  87.                                     getChildDrawingOrder(childrenCount, i) : i;  
  88.                             final View child = children[childIndex];  
  89.                             if (!canViewReceivePointerEvents(child)  
  90.                                     || !isTransformedTouchPointInView(x, y, child, null)) {  
  91.                                 if (DBG_MOTION) {  
  92.                                     Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent continue 6: i = "  
  93.                                             + i + ",count = " + childrenCount + ",child = " + child  
  94.                                             + ",this = " + this);  
  95.                                 }  
  96.                                 continue;  
  97.                             }  
  98.   
  99.                             newTouchTarget = getTouchTarget(child);  
  100.                             if (DBG_MOTION) {  
  101.                                 Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent to child 3: child = "  
  102.                                         + child + ",childrenCount = " + childrenCount + ",i = " + i  
  103.                                         + ",newTouchTarget = " + newTouchTarget + ",idBitsToAssign = "   
  104.                                         + idBitsToAssign + ",mFirstTouchTarget = " + mFirstTouchTarget   
  105.                                         + ",this = " + this);  
  106.                             }  
  107.                             if (newTouchTarget != null) {  
  108.                                 // Child is already receiving touch within its bounds.  
  109.                                 // Give it the new pointer in addition to the ones it is handling.  
  110.                                 newTouchTarget.pointerIdBits |= idBitsToAssign;  
  111.                                 break;  
  112.                             }  
  113.   
  114.                             resetCancelNextUpFlag(child);  
  115.                             if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {   // -------  
  116.                                 // Child wants to receive touch within its bounds.  
  117.                                 mLastTouchDownTime = ev.getDownTime();  
  118.                                 mLastTouchDownIndex = childIndex;  
  119.                                 mLastTouchDownX = ev.getX();  
  120.                                 mLastTouchDownY = ev.getY();  
  121.                                 newTouchTarget = addTouchTarget(child, idBitsToAssign);  
  122.                                 alreadyDispatchedToNewTouchTarget = true;  
  123.                                 break;  
  124.                             }  
  125.                         }  
  126.                     }  
  127.   
  128.                     if (newTouchTarget == null && mFirstTouchTarget != null) {  
  129.                         // Did not find a child to receive the event.  
  130.                         // Assign the pointer to the least recently added target.  
  131.                         newTouchTarget = mFirstTouchTarget;  
  132.                         while (newTouchTarget.next != null) {  
  133.                             newTouchTarget = newTouchTarget.next;  
  134.                         }  
  135.                         newTouchTarget.pointerIdBits |= idBitsToAssign;  
  136.                     }  
  137.                 }  
  138.             }  
  139.   
  140.             // Dispatch to touch targets.  
  141.             if (mFirstTouchTarget == null) {  
  142.                 if (DBG_MOTION) {  
  143.                     Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent mFirstTouchTarget = null, canceled = "  
  144.                             + canceled + ",this = " + this);  
  145.                 }  
  146.                 // No touch targets so treat this as an ordinary view.  
  147.                 handled = dispatchTransformedTouchEvent(ev, canceled, null,       //--------  
  148.                         TouchTarget.ALL_POINTER_IDS);  
  149.             } else {  
  150.                 // Dispatch to touch targets, excluding the new touch target if we already  
  151.                 // dispatched to it.  Cancel touch targets if necessary.  
  152.                 TouchTarget predecessor = null;  
  153.                 TouchTarget target = mFirstTouchTarget;  
  154.                 while (target != null) {  
  155.                     final TouchTarget next = target.next;  
  156.                     if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {  
  157.                         handled = true;  
  158.                     } else {  
  159.                         final boolean cancelChild = resetCancelNextUpFlag(target.child)  
  160.                                 || intercepted;  
  161.                         if (dispatchTransformedTouchEvent(ev, cancelChild,     //----------  
  162.                                 target.child, target.pointerIdBits)) {  
  163.                             handled = true;  
  164.                         }  
  165.                         if (DBG_MOTION) {  
  166.                             Xlog.d(TAG, "dispatchTouchEvent middle 5: cancelChild = " + cancelChild  
  167.                                     + ",mFirstTouchTarget = " + mFirstTouchTarget + ",target = "  
  168.                                     + target + ",predecessor = " + predecessor + ",next = " + next  
  169.                                     + ",this = " + this);  
  170.                         }  
  171.                         if (cancelChild) {  
  172.                             if (predecessor == null) {  
  173.                                 mFirstTouchTarget = next;  
  174.                             } else {  
  175.                                 predecessor.next = next;  
  176.                             }  
  177.                             target.recycle();  
  178.                             target = next;  
  179.                             continue;  
  180.                         }  
  181.                     }  
  182.                     predecessor = target;  
  183.                     target = next;  
  184.                 }  
  185.             }  
  186.   
  187.             // Update list of touch targets for pointer up or cancel, if needed.  
  188.             if (canceled  
  189.                     || actionMasked == MotionEvent.ACTION_UP  
  190.                     || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {  
  191.                 resetTouchState();  
  192.             } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {  
  193.                 final int actionIndex = ev.getActionIndex();  
  194.                 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);  
  195.                 removePointersFromTouchTargets(idBitsToRemove);  
  196.             }  
  197.         }  
  198.   
  199.         if (DBG_MOTION) {  
  200.             Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent end 4: handled = " + handled + ",mFirstTouchTarget = "  
  201.                     + mFirstTouchTarget + ",this = " + this);  
  202.         }  
  203.   
  204.         if (!handled && mInputEventConsistencyVerifier != null) {  
  205.             mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);  
  206.         }  
  207.         return handled;  
  208.     }  
    
      通过上面我标红色的代码(做标记地方,显示有问题),我们很明显的看得出来通过onInterceptTouchEvent最终交给了dispatchTransformedTouchEvent来处理,那么dispatchTransformedTouchEvent又做了什么呢
[java] view plaincopy
  1. private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,  
  2.             View child, int desiredPointerIdBits) {  
  3.         final boolean handled;  
  4.   
  5.         // Canceling motions is a special case.  We don't need to perform any transformations  
  6.         // or filtering.  The important part is the action, not the contents.  
  7.         final int oldAction = event.getAction();  
  8.         if (DBG_MOTION) {  
  9.             Xlog.d(TAG, "dispatchTransformedTouchEvent 1: event = " + event + ",cancel = "  
  10.                     + cancel + ",oldAction = " + oldAction + ",desiredPointerIdBits = "  
  11.                     + desiredPointerIdBits + ",mFirstTouchTarget = " + mFirstTouchTarget  
  12.                     + ",child = " + child + ",this = " + this);  
  13.         }  
  14.   
  15.         if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {  
  16.             event.setAction(MotionEvent.ACTION_CANCEL);  
  17.             if (child == null) {  
  18.                 handled = super.dispatchTouchEvent(event);  
  19.             } else {  
  20.                 handled = child.dispatchTouchEvent(event);  
  21.             }  
  22.             event.setAction(oldAction);  
  23.             if (DBG_MOTION) {  
  24.                 Xlog.d(TAG, "Dispatch cancel action end: handled = " + handled + ",oldAction = "  
  25.                         + oldAction + ",child = " + child + ",this = " + this);  
  26.             }  
  27.             return handled;  
  28.         }  
  29.   
  30.         // Calculate the number of pointers to deliver.  
  31.         final int oldPointerIdBits = event.getPointerIdBits();  
  32.         final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;  
  33.   
  34.         // If for some reason we ended up in an inconsistent state where it looks like we  
  35.         // might produce a motion event with no pointers in it, then drop the event.  
  36.         if (newPointerIdBits == 0) {  
  37.             Xlog.i(TAG, "Dispatch transformed touch event without pointers in " + this);  
  38.             return false;  
  39.         }  
  40.   
  41.         // If the number of pointers is the same and we don't need to perform any fancy  
  42.         // irreversible transformations, then we can reuse the motion event for this  
  43.         // dispatch as long as we are careful to revert any changes we make.  
  44.         // Otherwise we need to make a copy.  
  45.         final MotionEvent transformedEvent;  
  46.         if (newPointerIdBits == oldPointerIdBits) {  
  47.             if (child == null || child.hasIdentityMatrix()) {  
  48.                 if (child == null) {  
  49.                     handled = super.dispatchTouchEvent(event);  
  50.                 } else {  
  51.                     final float offsetX = mScrollX - child.mLeft;  
  52.                     final float offsetY = mScrollY - child.mTop;  
  53.                     event.offsetLocation(offsetX, offsetY);  
  54.   
  55.                     handled = child.dispatchTouchEvent(event);  
  56.   
  57.                     event.offsetLocation(-offsetX, -offsetY);  
  58.                 }  
  59.                 if (DBG_MOTION) {  
  60.                     Xlog.d(TAG, "dispatchTransformedTouchEvent 2 to child " + child  
  61.                             + ",handled = " + handled + ",mScrollX = " + mScrollX + ",mScrollY = "  
  62.                             + mScrollY + ",mFirstTouchTarget = " + mFirstTouchTarget + ",event = "  
  63.                             + event + ",this = " + this);  
  64.                 }  
  65.                 return handled;  
  66.             }  
  67.             transformedEvent = MotionEvent.obtain(event);  
  68.         } else {  
  69.             transformedEvent = event.split(newPointerIdBits);  
  70.         }  
  71.   
  72. // Perform any necessary transformations and dispatch.  
  73.         if (child == null) {  
  74.             handled = super.dispatchTouchEvent(transformedEvent);  
  75.         } else {  
  76.             final float offsetX = mScrollX - child.mLeft;  
  77.             final float offsetY = mScrollY - child.mTop;  
  78.             transformedEvent.offsetLocation(offsetX, offsetY);  
  79.             if (! child.hasIdentityMatrix()) {  
  80.                 transformedEvent.transform(child.getInverseMatrix());  
  81.             }  
  82.   
  83.             handled = child.dispatchTouchEvent(transformedEvent);  
  84.         }  
  85.   
  86.         if (DBG_MOTION) {  
  87.             Xlog.d(TAG, "dispatchTransformedTouchEvent 3 to child " + child + ",handled = "  
  88.                     + handled + ",mScrollX = " + mScrollX + ",mScrollY = " + mScrollY  
  89.                     + ",mFirstTouchTarget = " + mFirstTouchTarget + ",transformedEvent = "  
  90.                     + transformedEvent + ",this = " + this);  
  91.         }  
  92.   
  93.         // Done.  
  94.         transformedEvent.recycle();  
  95.         return handled;  
  96.     }  

        从上面的代码来判断我们假设我们不重载
[java] view plaincopy
  1. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  2.         return false;  
  3.     }  

那么很明显了,我们的ViewGroup不会吃掉本次MotionEvent
从上一博文中的MyImageView被点击来判断
当我们点击我们ImageView时


我们继续接着我们的Log来分析
MotionEvent事件首先传递给了我们的MyFrameLayout,这时,我们要注意虽然我们设置了onTouchListener和OnClickListener,但是因为我们没有重载onInterceptTouchEvent默认的onInterceptTouchEvent直接return false;所以我们的MyFrameLayout没有资格消费本次的MotionEvent事件,最终经过判断dispatchTransformedTouchEvent把事件交给了我们的MyImageView
[java] view plaincopy
  1. handled = child.dispatchTouchEvent(transformedEvent);  
当然 因为我们的MyImageView 也设置了onTouchListener和onClickListener,所以他顺理成章的消费了本次MotionEvent

当我们再点击我们FrameLayout
这时虽然我们的onInterceptTouchEvent还是return  false;但是我们的touchTarget是空的,所以
[java] view plaincopy
  1. if (child == null) {  
  2.             handled = super.dispatchTouchEvent(transformedEvent);  
  3.         } else   
我们的MyFrameLayout 也还是最终享受到了MotionEvent
  所以说  不一定我们的onInterceptTouchEvent 返回了false 我们的ViewGroup就不能接收到OnTouchEvent了


这里,我们再次考虑  当我们的onInterceptTouchEvent 被我们重载  并返回了true 那么走的路线就不一样了
[java] view plaincopy
  1. if (!canceled && !intercepted) {     //依据interceptd 分析转折点</span>  
[java] view plaincopy
  1. if (mFirstTouchTarget == null) {  
  2.                 if (DBG_MOTION) {  
  3.                     Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent mFirstTouchTarget = null, canceled = "  
  4.                             + canceled + ",this = " + this);  
  5.                 }  
  6.                 // No touch targets so treat this as an ordinary view.  
  7.                 handled = dispatchTransformedTouchEvent(ev, canceled, null,  
  8.                         TouchTarget.ALL_POINTER_IDS);  

这里注意,因为我们的onInterceptTouchEvent return true;我们直接跳过了Child的判断并最终导致我们的child == null;那么很明星我们的MotionEvent只能被我们的ViewGroup消费了。
        那么,到了这里我们开始大胆的做出假设性结论:
        一、只要我们的onInterceptTouchEvent return true 那么我们的MotionEvent 与ChildView 无缘
         二、如果我们的onInterceptTouchEvent  return false;那么我们的ChildView  会优先获得MotionEvent ,但是当我们的ChildView  并不在TouchTarget上,我们的ViewGroup依然有机会得到本次MotionEvent 。
     那么接下来,我们所有做的就只能验证我们的结论了。
    这里我们先验证第一条// 这里的验证我们将依据ACTION的不同来分析。
    这里我们对我们的MyFrameLayout  做出改变(重载onInterceptTouchEvent 
[java] view plaincopy
  1. @Override  
  2.     public boolean onInterceptTouchEvent(MotionEvent event) {  
  3.         switch(event.getAction()){  
  4.         case MotionEvent.ACTION_DOWN:{  
  5.             Log.d(TAG,"MyFrameLayout onInterceptTouchEvent ACTION_DOWN return true");  
  6.             return true;  
  7.         }  
  8.         case MotionEvent.ACTION_MOVE:{  
  9.             Log.d(TAG,"MyFrameLayout onInterceptTouchEvent ACTION_MOVE return true");  
  10.             return true;  
  11.         }  
  12.         case MotionEvent.ACTION_UP:{  
  13.             Log.d(TAG,"MyFrameLayout onInterceptTouchEvent ACTION_UP return true");  
  14.             return true;  
  15.         }  
  16.         }  
  17.         return true;  
  18.     }  

简而言之,就是不论什么情况下,我们都要我们的onInterceptTouchEvent  return true;
并分别改写我们的FrameLayout 和ImageView的OnTouchEvent函数
[java] view plaincopy
  1. @Override  
  2.    public boolean onTouchEvent(MotionEvent event) {  
  3.        Log.d(TAG,"MyFrameLayout onTouchEvent"+event.getAction());  
  4.        switch(event.getAction()){  
  5.        case MotionEvent.ACTION_DOWN:{  
  6.            Log.d(TAG,"MyFrameLayout onTouchEvent ACTION_DOWN return true");  
  7.            break;  
  8.        }  
  9.        case MotionEvent.ACTION_MOVE:{  
  10.            Log.d(TAG,"MyFrameLayout onTouchEvent ACTION_MOVE return true");  
  11.            break;  
  12.        }  
  13.        case MotionEvent.ACTION_UP:{  
  14.            Log.d(TAG,"MyFrameLayout onTouchEvent ACTION_UP return true");  
  15.            break;  
  16.        }  
  17.        }  
  18.        return super.onTouchEvent(event);  
  19.    }  

[java] view plaincopy
  1. @Override  
  2.    public boolean onTouchEvent(MotionEvent event) {  
  3.        Log.d(TAG,"MyImageView onTouchEvent"+event.getAction());  
  4.        switch(event.getAction()){  
  5.        case MotionEvent.ACTION_DOWN:{  
  6.            Log.d(TAG,"MyImageView onTouchEvent ACTION_DOWN return true");  
  7.            break;  
  8.        }  
  9.        case MotionEvent.ACTION_MOVE:{  
  10.            Log.d(TAG,"MyImageView onTouchEvent ACTION_MOVE return true");  
  11.            break;  
  12.        }  
  13.        case MotionEvent.ACTION_UP:{  
  14.            Log.d(TAG,"MyImageView onTouchEvent ACTION_UP return true");  
  15.            break;  
  16.        }  
  17.        }  
  18.        return super.onTouchEvent(event);  
  19.    }  

   首先我们点击我们的MyImageView,我们来看一下Log


很明显,一旦我们的onInterceptTouchEvent  return true,我们的子View就与MotionEvent 无缘了

接下来,我们继续点击我们的FrameLayout
Log 图,我就不贴了,和上面一模一样,为什么呢,很显然我们的子View就与MotionEvent 无缘了

接下来,我们继续做出改变
我们在FrameLayout中将onInterceptTouchEvent  中的MotionEvent.ACTION_DOWN returnfalse;
依然点击我们的点击我们的MyImageView


这里我们来分析一下Log   首先我们需要知道3 == MotionEvent.ACTION_CANCEL
那么,首先因为我们的onInterceptTouchEvent  在MotionEvent.ACTION_DOWN returnfalse;所以我们的FrameLayout没办法继续往下走了(不会走onTouch 和 onTouchEvent)转而MotionEvent事件转交给我们的ImageView
所以我们的ImageView总算是得到了MotionEvent.ACTION_DOWN
但是在经过MotionEvent.ACTION_MOVE时,因为我们的onInterceptTouchEvent  返回了true,所以很明显我们的FrameLayout告诉了系统 这次的MotionEvent事件我要了,所以我们的ImageView的到了MotionEvent.ACTION_CANCEL  反而我们的FrameLayout 可以继续往下走了。
所以说我们的ImageView猜中了开头缺有猜中结局,虽然得到了ACTION_DOWN,但却什么都做不了只能以ACTION_CANCEL草草收场,所以也不会触发onClickListener

同理我们的FrameLayout虽然得到了ACTION_UP 但是没有ACTION_DOWN 也是徒劳。同样不会OnClickListener

到了这里,我们同样也是可以类推的 如果我们的FrameLayout在onInterceptTouchEvent  在ACTION_MOVE中返回false,我们的ImageView可以接受到ACTION_MOVE 但是最终接受的还是ACTION_CANCEL依然接受不到ACTION_UP ,反而我们的FrameLayout 只能得到ACTION_UP ,简而言之就是说依据onInterceptTouchEvent  的返回值不同各MotionEvent事件最终要么被ViewGroup 要么被ChildView获取

从上面的Log,我们依然可以看到的是 onInterceptTouchEvent 并不会在每一次 MotionEvent事件(ACTION_DOWN、ACTION_MOVE、ACTION_UP 等)调用,例如果在ACTION_DOWN return true 交给了ViewGroup 而View没有得到的话,ACTION_MOVE时就不会调用,但是如果return false,ChildView 得到了ACTION_MOVE时就会再次调用
0 0
原创粉丝点击