android 事件分发源码解析

转载:https://blog.csdn.net/lfdfhl/article/details/50707724

  1. package cc.aa;  
  2.   
  3. import android.os.Environment;  
  4. import android.view.MotionEvent;  
  5. import android.view.View;  
  6.   
  7. public class UnderstandDispatchTouchEvent {  
  8.     /** 
  9.      * 该示例的重点: 
  10.      * 1 ViewGroup的dispatchTouchEvent()源码学习及其注释 
  11.      * 2 ViewGroup的dispatchTransformedTouchEvent()源码学习及其注释 
  12.      * 3 弄明白两个问题: 
  13.      *   (1)为什么某个子View对于ACTION_DOWN返回false,那么系统不会讲ACTION_MOVE和ACTION_UP派发给该子View. 
  14.      *   因为ACTION_DOWN是一系列Touch事件的开端,如果子View对于该ACTION_DOWN事件在onTouchEvent()中返回了false即未消费. 
  15.      *   那么ViewGroup就不会把后续的ACTION_MOVE和ACTION_UP派发给该子View.在这种情况下ViewGroup就和普通的View一样了, 
  16.      *   调用该ViewGroup自己的dispatchTouchEvent()从而调用自己的onTouchEvent();即不会将事件分发给子View. 
  17.      *   详细代码请参见如下代码分析. 
  18.      *    
  19.      *   (2)为什么子view对于Touch事件处理返回true那么其上层的ViewGroup就无法处理Touch事件了 
  20.      *   这个想必大家都知道了,因为该Touch事件被子View消费了其上层的ViewGroup就无法处理该Touch事件了. 
  21.      *   那么在源码中的依据是什么呢?请看下面的源码分析 
  22.      *    
  23.      *  
  24.      * 常说事件传递中的流程是: 
  25.      * dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent 
  26.      * 在这个链条中dispatchTouchEvent()是处在链首的位置当然也是最重要的. 
  27.      * 在dispatchTouchEvent()决定了Touch事件是由自己的onTouchEvent()处理 
  28.      * 还是分发给子View处理让子View调用其自身的dispatchTouchEvent()处理. 
  29.      *  
  30.      *  
  31.      * 其实dispatchTouchEvent()和onInterceptTouchEvent()以及onTouchEvent()的关系 
  32.      * 在dispatchTouchEvent()方法的源码中体现得很明显. 
  33.      * 比如dispatchTouchEvent()会调用onInterceptTouchEvent()来判断是否要拦截. 
  34.      * 比如dispatchTouchEvent()会调用dispatchTransformedTouchEvent()方法且在该方法中递归调用 
  35.      * dispatchTouchEvent();从而会在dispatchTouchEvent()里最终调用到onTouchEvent() 
  36.      *  
  37.      *  
  38.      *  
  39.      *    
  40.      * 参考资料: 
  41.      * 0 http://blog.csdn.net/sahadev_/article/details/23839039 
  42.      * 1 http://wangkuiwu.github.io/2015/01/04/TouchEvent-ViewGroup/ 
  43.      * 2 http://www.cnblogs.com/xiaoweiz/p/3838682.html 
  44.      * 3 http://hukai.me/android-deeper-touch-event-dispatch-process/ 
  45.      * 4 http://blog.csdn.net/yanbober/article/details/45912661 
  46.      * 5 http://www.eoeandroid.com/thread-542296-1-1.html 
  47.      * 6 http://www.eoeandroid.com/forum.php?mod=viewthread&tid=319301 
  48.      * 7 http://stackvoid.com/details-dispatch-onTouch-Event-in-Android/ 
  49.      *   Thank you very much 
  50.      */  
  51.       
  52.     @Override  
  53.     public boolean dispatchTouchEvent(MotionEvent ev) {  
  54.         if (mInputEventConsistencyVerifier != null) {  
  55.             mInputEventConsistencyVerifier.onTouchEvent(ev, 1);  
  56.         }  
  57.   
  58.         boolean handled = false;  
  59.         if (onFilterTouchEventForSecurity(ev)) {  
  60.             final int action = ev.getAction();  
  61.             final int actionMasked = action & MotionEvent.ACTION_MASK;  
  62.   
  63.             /** 
  64.              * 第一步:对于ACTION_DOWN进行处理(Handle an initial down) 
  65.              * 因为ACTION_DOWN是一系列事件的开端,当是ACTION_DOWN时进行一些初始化操作. 
  66.              * 从源码的注释也可以看出来:清除以往的Touch状态(state)开始新的手势(gesture) 
  67.              * cancelAndClearTouchTargets(ev)中有一个非常重要的操作: 
  68.              * 将mFirstTouchTarget设置为null!!!! 
  69.              * 随后在resetTouchState()中重置Touch状态标识 
  70.              */  
  71.             if (actionMasked == MotionEvent.ACTION_DOWN) {  
  72.                 // Throw away all previous state when starting a new touch gesture.  
  73.                 // The framework may have dropped the up or cancel event for the previous gesture  
  74.                 // due to an app switch, ANR, or some other state change.  
  75.                 cancelAndClearTouchTargets(ev);  
  76.                 resetTouchState();  
  77.             }  
  78.   
  79.               
  80.             /** 
  81.              * 第二步:检查是否要拦截(Check for interception) 
  82.              * 在哪些情况下会调用该代码呢?有如下几种情况 
  83.              * 1 处理ACTION_DOWN事件 
  84.              * 2 当ACTION_DOWN事件被子View消费后处理ACTION_MOVE和ACTION_UP时 
  85.              *  会调用该代码。因为此时mFirstTouchTarget!=null。所以此时ViewGroup 
  86.              *  是有机会拦截ACTION_MOVE和ACTION_UP的,但是我们也可以调用方法: 
  87.              *  requestDisallowInterceptTouchEvent来禁止ViewGroup的事件拦截. 
  88.              *  如果子View没有消费Touch事件,那么那么当后续的ACTION_MOVE和ACTION_UP 
  89.              *  到来时是不会调用到本处代码的. 
  90.              *   
  91.              * 在dispatchTouchEvent(MotionEventev)这一大段代码中 
  92.              * 使用变量intercepted来标记ViewGroup是否拦截Touch事件的传递. 
  93.              * 该变量在后续代码中起着很重要的作用. 
  94.              *  
  95.              * 从此处if(actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null)及其内部代码可知: 
  96.              * 当ViewGroup决定拦截事件后,那么后续的点击事件将会默认交给它处理,不再调用 
  97.              * onInterceptTouchEvent()判断是否需要拦截. 
  98.              * 这个是为什么? 
  99.              * 因为在处理ACTION_DOWN时如果Touch事件被子View消费,那么mFirstTouchTarget不为空; 
  100.              * 反之,如果Touch事件没有被子View消费,那么mFirstTouchTarget为空,即此时Touch由当前 
  101.              * 的ViewGroup拦截。此时当ACTION_MOVE和ACTION_UP来到时,不再满足: 
  102.              * if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) 
  103.              * 当然也就无法调用其内部的onInterceptTouchEvent()。 
  104.              * 通俗地说:一旦ViewGroup拦截了ACTION_DOWN事件由自身的onTouchEvent()处理,那么 
  105.              * 对于后续的ACTION_MOVE和ACTION_UP而言ViewGroup不再调用onInterceptTouchEvent() 
  106.              * 判断是否拦截. 
  107.              *  
  108.              * 这里有个东西需要注意:FLAG_DISALLOW_INTERCEPT 
  109.              * 在子View中调用requestDisallowInterceptTouchEvent()后造成disallowIntercept为true 
  110.              * 即禁止拦截.于是不满足if(!disallowIntercept)所以也就调用不到该if内的onInterceptTouchEvent() 
  111.              * 自然就没有办法拦截了. 
  112.              * 但是requestDisallowInterceptTouchEvent()对于ACTION_DOWN是无效的. 
  113.              * 因为对于ACTION_DOWN会调用 cancelAndClearTouchTargets(ev)和resetTouchState(); 
  114.              * 对FLAG_DISALLOW_INTERCEPT等状态值复原重置(参考上面的代码) 
  115.              *  
  116.              * 举两种情况说明: 
  117.              * 1 当处理ACTION_DOWN时当然会满足 
  118.              *  if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) 
  119.              *  对于ACTION_DOWN子View有两种处理结果 
  120.              *  1.1 消耗了Touch事件,那么mFirstTouchTarget不为null. 
  121.              *      所以处理后续的ACTION_MOVE和ACTION_UP时依然满足该if判断 
  122.              *  1.2 没有消耗Touch事件.mFirstTouchTarget=null.不满足该if. 
  123.              *      所以后续的ACTION_MOVE和ACTION_UP由ViewGroup处理,此时再讨论什么拦截也就没有意义了. 
  124.              *      同样的道理当子View消费了ACTION_DOWN后当处理ACTION_MOVE的时候ViewGroup拦截了该事件 
  125.              *      那么当ACTION_UP随之到来时由于mFirstTouchTarget=null所以不会再调用该段代码,自然也就 
  126.              *      不会调用onInterceptTouchEvent()判断是否拦截了.这点在上面的注释也有提及 
  127.              * 2 当出现1.1的情况时满足该if判断. 
  128.              *  如果在子View中调用了requestDisallowInterceptTouchEvent()那么就禁止拦截 
  129.              *  即disallowIntercept=true.所以不满足if (!disallowIntercept)当然也就调用不到 
  130.              *  onInterceptTouchEvent(ev)了,而是执行else{ intercepted = false;} 
  131.              *  也就是说ViewGroup无法拦截Touch了. 
  132.              */  
  133.             final boolean intercepted;  
  134.             // 事件为ACTION_DOWN或者mFirstTouchTarget不为null(即已经找到能够接收touch事件的目标组件)时if成立  
  135.             if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {  
  136.                 //判断disallowIntercept(禁止拦截)标志位  
  137.                 //因为在其他地方可能调用了requestDisallowInterceptTouchEvent()改变该值.  
  138.                 //对于此方法的作用其实看requestDisallowInterceptTouchEvent()这个方法名就可明白了  
  139.                 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  
  140.                 //当禁止拦截为false时(即disallowIntercept为false)调用onInterceptTouchEvent(ev)方法  
  141.                 if (!disallowIntercept) {  
  142.                     //既然disallowIntercept为false那么就调用onInterceptTouchEvent()方法将结果赋值给intercepted  
  143.                     //常说事件传递中的流程是:dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent  
  144.                     //其实在这就是一个体现,在dispatchTouchEvent()中调用了onInterceptTouchEvent()  
  145.                     intercepted = onInterceptTouchEvent(ev);  
  146.                     ev.setAction(action); // restore action in case it was changed  
  147.                 } else {  
  148.                     //禁止拦截的FLAG为ture说明没有必要去执行是否需要拦截了能够顺利通过,所以设置拦截变量为false  
  149.                     //即当禁止拦截为true时(即disallowIntercept为true)设置intercepted = false  
  150.                     intercepted = false;  
  151.                 }  
  152.             } else {  
  153.                 //当事件不是ACTION_DOWN并且mFirstTouchTarget为null(即没有Touch的目标组件)时  
  154.                 //设置 intercepted = true表示ViewGroup执行Touch事件拦截的操作。  
  155.                 //There are no touch targets and this action is not an initial down  
  156.                 //so this view group continues to intercept touches.  
  157.                 intercepted = true;  
  158.             }  
  159.   
  160.               
  161.             /** 
  162.              * 第三步:检查cancel(Check for cancelation) 
  163.              *  
  164.              */  
  165.             final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;  
  166.   
  167.               
  168.             /** 
  169.              * 第四步:事件分发(Update list of touch targets for pointer down, if needed) 
  170.              */  
  171.             final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;  
  172.             TouchTarget newTouchTarget = null;  
  173.             boolean alreadyDispatchedToNewTouchTarget = false;  
  174.             //不是ACTION_CANCEL并且ViewGroup的拦截标志位intercepted为false(不拦截)  
  175.             if (!canceled && !intercepted) {  
  176.                 //处理ACTION_DOWN事件.这个环节比较繁琐.  
  177.                 if (actionMasked == MotionEvent.ACTION_DOWN  
  178.                     || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)  
  179.                     || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {  
  180.                     final int actionIndex = ev.getActionIndex(); // always 0 for down  
  181.                     final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex):TouchTarget.ALL_POINTER_IDS;  
  182.   
  183.                     // Clean up earlier touch targets for this pointer id in case they  
  184.                     // have become out of sync.  
  185.                     removePointersFromTouchTargets(idBitsToAssign);  
  186.   
  187.                     final int childrenCount = mChildrenCount;  
  188.                     if (childrenCount != 0) {  
  189.                         // 依据Touch坐标寻找子View来接收Touch事件  
  190.                         // Find a child that can receive the event.  
  191.                         // Scan children from front to back.  
  192.                         final View[] children = mChildren;  
  193.                         final float x = ev.getX(actionIndex);  
  194.                         final float y = ev.getY(actionIndex);  
  195.   
  196.                         final boolean customOrder = isChildrenDrawingOrderEnabled();  
  197.                         // 遍历子View判断哪个子View接受Touch事件  
  198.                         for (int i = childrenCount - 1; i >= 0; i–) {  
  199.                             final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;  
  200.                             final View child = children[childIndex];  
  201.                             if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) {  
  202.                                 continue;  
  203.                             }  
  204.   
  205.                             newTouchTarget = getTouchTarget(child);  
  206.                             if (newTouchTarget != null) {  
  207.                                 // 找到接收Touch事件的子View!!!!!!!即为newTouchTarget.  
  208.                                 // 既然已经找到了,所以执行break跳出for循环  
  209.                                 // Child is already receiving touch within its bounds.  
  210.                                 // Give it the new pointer in addition to the ones it is handling.  
  211.                                 newTouchTarget.pointerIdBits |= idBitsToAssign;  
  212.                                 break;  
  213.                             }  
  214.   
  215.                             resetCancelNextUpFlag(child);  
  216.                             /** 
  217.                              * 如果上面的if不满足,当然也不会执行break语句. 
  218.                              * 于是代码会执行到这里来. 
  219.                              *  
  220.                              *  
  221.                              * 调用方法dispatchTransformedTouchEvent()将Touch事件传递给子View做 
  222.                              * 递归处理(也就是遍历该子View的View树) 
  223.                              * 该方法很重要,看一下源码中关于该方法的描述: 
  224.                              * Transforms a motion event into the coordinate space of a particular child view, 
  225.                              * filters out irrelevant pointer ids, and overrides its action if necessary. 
  226.                              * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead. 
  227.                              * 将Touch事件传递给特定的子View. 
  228.                              * 该方法十分重要!!!!!!!!!!!!!!!!! 
  229.                              * 在该方法中为一个递归调用,会递归调用dispatchTouchEvent()方法!!!!!!!!!! 
  230.                              * 在dispatchTouchEvent()中: 
  231.                              * 如果子View为ViewGroup并且Touch没有被拦截那么递归调用dispatchTouchEvent() 
  232.                              * 如果子View为View那么就会调用其onTouchEvent(),这个不再赘述. 
  233.                              *  
  234.                              *  
  235.                              * 该方法返回true则表示子View消费掉该事件,同时进入该if判断. 
  236.                              * 满足if语句后重要的操作有: 
  237.                              * 1 给newTouchTarget赋值 
  238.                              * 2 给alreadyDispatchedToNewTouchTarget赋值为true. 
  239.                              *   看这个比较长的英语名字也可知其含义:已经将Touch派发给新的TouchTarget 
  240.                              * 3 执行break. 
  241.                              *   因为该for循环遍历子View判断哪个子View接受Touch事件,既然已经找到了 
  242.                              *   那么就跳出该for循环. 
  243.                              * 4 注意: 
  244.                              *   如果dispatchTransformedTouchEvent()返回false即子View的onTouchEvent返回false 
  245.                              *   (即Touch事件未被消费)那么就不满足该if条件.所以也就无法执行addTouchTarget(). 
  246.                              *   在此简单说一下addTouchTarget()中涉及到的ViewGroup的一个内部类TouchTarget——它是一个事件链. 
  247.                              *   该处的mFirstTouchTarget就是一个TouchTarget.它保存了可以消耗Touch事件的View. 
  248.                              *   在该处,如果dispatchTransformedTouchEvent()返回true即子View的onTouchEvent返回true则说明 
  249.                              *   该View消耗了Touch事件,那么将该View加入到事件链中!!!!!!!!!!!!!!! 
  250.                              *   尤其注意: 
  251.                              *   这个操作是在处理ACTION_DOWN的代码块里进行的.即是在: 
  252.                              *    if (actionMasked == MotionEvent.ACTION_DOWN||  
  253.                              *    (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) ||  
  254.                              *    actionMasked == MotionEvent.ACTION_HOVER_MOVE) 
  255.                              *    这个大的if判断中处理的. 
  256.                              *    当处理ACTION_MOVE事件和ACTION_UP事件的时候是不会进入这个if判断的!!!!! 
  257.                              *    而是直接从去判断mFirstTouchTarget!!!!!!!!!!!!!!!! 
  258.                              *    所以如果一个View不处理ACTION_DOWN那么该,那么该View是不会保存在mFirstTouchTarget 
  259.                              *    中的,也就无法继续处理ACTION_MOVE事件和ACTION_UP事件!!!!!!!!!!即若该View不消耗 
  260.                              *    ACTION_DOWN事件那么系统是不会讲ACTION_MOVE和ACTION_UP事件传给给该View的 
  261.                              * 5 注意: 
  262.                              *   如果dispatchTransformedTouchEvent()返回true即子View 
  263.                              *   的onTouchEvent返回true(即Touch事件被消费)那么就满足该if条件. 
  264.                              *   从而mFirstTouchTarget不为null!!!!!!!!!!!!!!!!!!! 
  265.                              * 6 小结: 
  266.                              *   对于此处ACTION_DOWN的处理具体体现在dispatchTransformedTouchEvent() 
  267.                              *   该方法返回boolean,如下: 
  268.                              *   true—->事件被消费—–>mFirstTouchTarget!=null 
  269.                              *   false—>事件未被消费—>mFirstTouchTarget==null 
  270.                              *   因为在dispatchTransformedTouchEvent()会调用递归调用dispatchTouchEvent()和onTouchEvent() 
  271.                              *   所以dispatchTransformedTouchEvent()的返回值实际上是由onTouchEvent()决定的. 
  272.                              *    
  273.                              *   简单地说onTouchEvent()是否消费了Touch事件(true or false)的返回值决定了 
  274.                              *   dispatchTransformedTouchEvent()的返回值!!!!从而决定了mFirstTouchTarget是否为null!!!!!! 
  275.                              *   从而进一步决定了ViewGroup是否处理Touch事件.这一点在下面的代码中很有体现. 
  276.                              */  
  277.                             if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {  
  278.                                 // Child wants to receive touch within its bounds.  
  279.                                 mLastTouchDownTime = ev.getDownTime();  
  280.                                 mLastTouchDownIndex = childIndex;  
  281.                                 mLastTouchDownX = ev.getX();  
  282.                                 mLastTouchDownY = ev.getY();  
  283.                                 //调用addTouchTarget()将child添加到mFirstTouchTarget链表的表头  
  284.                                 //注意在addTouchTarget()方法内部会对mFirstTouchTarget操作,使其不为null  
  285.                                 newTouchTarget = addTouchTarget(child, idBitsToAssign);  
  286.                                 alreadyDispatchedToNewTouchTarget = true;  
  287.                                 break;  
  288.                             }  
  289.                         }//for循环结束  
  290.                     }  
  291.   
  292.                       
  293.                     /** 
  294.                      * 该if条件表示: 
  295.                      * 经过前面的for循环没有找到子View接收Touch事件并且之前的mFirstTouchTarget不为空 
  296.                      */  
  297.                     if (newTouchTarget == null && mFirstTouchTarget != null) {  
  298.                         // Did not find a child to receive the event.  
  299.                         // Assign the pointer to the least recently added target.  
  300.                         newTouchTarget = mFirstTouchTarget;  
  301.                         while (newTouchTarget.next != null) {  
  302.                             newTouchTarget = newTouchTarget.next;  
  303.                         }  
  304.                         //newTouchTarget指向了最初的TouchTarget  
  305.                         newTouchTarget.pointerIdBits |= idBitsToAssign;  
  306.                     }//处理ACTION_DOWN结束  
  307.                 }  
  308.             }  
  309.   
  310.               
  311.               
  312.             /** 
  313.              * 经过上面对于ACTION_DOWN的处理后mFirstTouchTarget有两种情况: 
  314.              * (当然如果不是ACTION_DOWN就不会经过上面较繁琐的流程而是从此处开始执行,比如ACTION_MOVE和ACTION_UP) 
  315.              *  
  316.              * 情况1 mFirstTouchTarget为null 
  317.              *       即没有找到能够消费touch事件的子组件或者是touch事件被拦截了 
  318.              * 情况2 mFirstTouchTarget不为null 
  319.              *       即找到了能够消费touch事件的子组件则后续的touch事件都可以传递到子View 
  320.              * 这两种情况的详细分析见下. 
  321.              *  
  322.              * 这两种情况下都会去调用方法: 
  323.              * dispatchTransformedTouchEvent(MotionEvent event,boolean cancel,View child,int desiredPointerIdBits) 
  324.              * 我们重点关注该方法的第三个参数View child. 
  325.              * 详情请参加下面dispatchTransformedTouchEvent()源码分析 
  326.              * 在该源码中解释了: 
  327.              * 为什么子view对于Touch事件处理返回true那么其上层的ViewGroup就无法处理Touch事件了!!!!!!!!! 
  328.              * 为什么子view对于Touch事件处理返回false那么其上层的ViewGroup才可以处理Touch事件!!!!!!!!!! 
  329.              *  
  330.              */  
  331.             if (mFirstTouchTarget == null) {  
  332.                 /** 
  333.                  * 情况1:mFirstTouchTarget为null 
  334.                  *  
  335.                  * 经过上面的分析mFirstTouchTarget为null就是说Touch事件未被消费. 
  336.                  * 即没有找到能够消费touch事件的子组件或Touch事件被拦截了, 
  337.                  * 则调用ViewGroup的dispatchTransformedTouchEvent()方法处理Touch事件则和普通View一样. 
  338.                  * 即子View没有消费Touch事件,那么子View的上层ViewGroup才会调用其onTouchEvent()处理Touch事件. 
  339.                  * 在源码中的注释为:No touch targets so treat this as an ordinary view. 
  340.                  * 也就是说此时ViewGroup像一个普通的View那样调用dispatchTouchEvent(),且在dispatchTouchEvent() 
  341.                  * 中会去调用onTouchEvent()方法. 
  342.                  * 具体的说就是在调用dispatchTransformedTouchEvent()时第三个参数为null. 
  343.                  * 第三个参数View child为null会做什么样的处理呢? 
  344.                  * 请参见下面dispatchTransformedTouchEvent()的源码分析 
  345.                  */  
  346.                 handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);  
  347.             } else {  
  348.                 /** 
  349.                  * 情况2:mFirstTouchTarget不为null 
  350.                  * 即找到了可以消费Touch事件的子View且后续Touch事件可以传递到该子View 
  351.                  * 在源码中的注释为: 
  352.                  * Dispatch to touch targets, excluding the new touch target if we already dispatched to it.   
  353.                  * Cancel touch targets if necessary. 
  354.                  */  
  355.                 TouchTarget predecessor = null;  
  356.                 TouchTarget target = mFirstTouchTarget;  
  357.                 while (target != null) {  
  358.                     final TouchTarget next = target.next;  
  359.                     if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {  
  360.                         //如果前面利用ACTION_DOWN事件寻找符合接收条件的子组件的同时消费掉了ACTION_DOWN事件  
  361.                         //那么这里为handled赋值为true  
  362.                         handled = true;  
  363.                     } else {  
  364.                         final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;  
  365.                         //对于非ACTION_DOWN事件继续传递给目标子组件进行处理  
  366.                         //依然是递归调用dispatchTransformedTouchEvent()  
  367.                         if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) {  
  368.                             handled = true;  
  369.                         }  
  370.                         if (cancelChild) {  
  371.                             if (predecessor == null) {  
  372.                                 mFirstTouchTarget = next;  
  373.                             } else {  
  374.                                 predecessor.next = next;  
  375.                             }  
  376.                             target.recycle();  
  377.                             target = next;  
  378.                             continue;  
  379.                         }  
  380.                     }  
  381.                     predecessor = target;  
  382.                     target = next;  
  383.                 }  
  384.             }  
  385.   
  386.             /** 
  387.              * 处理ACTION_UP和ACTION_CANCEL 
  388.              * Update list of touch targets for pointer up or cancel, if needed. 
  389.              * 在此主要的操作是还原状态 
  390.              */  
  391.             if (canceled|| actionMasked == MotionEvent.ACTION_UP  
  392.                         || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {  
  393.                 resetTouchState();  
  394.             } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {  
  395.                 final int actionIndex = ev.getActionIndex();  
  396.                 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);  
  397.                 removePointersFromTouchTargets(idBitsToRemove);  
  398.             }  
  399.         }  
  400.   
  401.         if (!handled && mInputEventConsistencyVerifier != null) {  
  402.             mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);  
  403.         }  
  404.         return handled;  
  405.     }  
  406.       
  407.       
  408.       
  409.     //=====================以上为dispatchTouchEvent()源码分析======================  
  410.       
  411.       
  412.       
  413.       
  414.       
  415.       
  416.       
  417.     //===============以下为dispatchTransformedTouchEvent()源码分析=================  
  418.       
  419.     /** 
  420.      * 在dispatchTouchEvent()中会调用dispatchTransformedTouchEvent()将事件分发给子View处理 
  421.      *  
  422.      * Transforms a motion event into the coordinate space of a particular child view, 
  423.      * filters out irrelevant pointer ids, and overrides its action if necessary. 
  424.      * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead. 
  425.      *  
  426.      * 在此请着重注意第三个参数:View child 
  427.      * 在dispatchTouchEvent()中多次调用dispatchTransformedTouchEvent(),但是有时候第三个参数为null,有时又不是. 
  428.      * 那么这个参数是否为null有什么区别呢? 
  429.      * 在如下dispatchTransformedTouchEvent()源码中可见多次对于child是否为null的判断,并且均做出如下类似的操作: 
  430.      * if (child == null) { 
  431.      *       handled = super.dispatchTouchEvent(event); 
  432.      *    } else { 
  433.      *       handled = child.dispatchTouchEvent(event); 
  434.      * } 
  435.      * 这个代码是什么意思呢? 
  436.      *  
  437.      * 当child == null时会将Touch事件传递给该ViewGroup自身的dispatchTouchEvent()处理. 
  438.      * 即super.dispatchTouchEvent(event) 
  439.      * 正如源码中的注释描述的一样: 
  440.      * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead. 
  441.      *  
  442.      * 当child != null时会调用该子view(当然该view可能是一个View也可能是一个ViewGroup)的dispatchTouchEvent(event)处理. 
  443.      * 即child.dispatchTouchEvent(event); 
  444.      *  
  445.      * 那么该child是否为null又是由什么决定的呢? 
  446.      * 在dispatchTouchEvent()中已经知道了: 
  447.      * 如果Touch事件被消耗掉那么child不为null 
  448.      * 如果Touch事件未被消耗掉那么child为null 
  449.      *  
  450.      * 这就解释了: 
  451.      * 为什么子view对于Touch事件处理返回true那么其上层的ViewGroup就无法处理Touch事件了!!!!!!!!! 
  452.      * 为什么子view对于Touch事件处理返回false那么其上层的ViewGroup才可以处理Touch事件!!!!!!!!!! 
  453.      */  
  454.     private boolean dispatchTransformedTouchEvent(MotionEvent event,boolean cancel,View child,int desiredPointerIdBits) {  
  455.         final boolean handled;  
  456.         // Canceling motions is a special case.  We don’t need to perform any transformations  
  457.         // or filtering.  The important part is the action, not the contents.  
  458.         final int oldAction = event.getAction();  
  459.         if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {  
  460.             event.setAction(MotionEvent.ACTION_CANCEL);  
  461.             if (child == null) {  
  462.                 handled = super.dispatchTouchEvent(event);  
  463.             } else {  
  464.                 handled = child.dispatchTouchEvent(event);  
  465.             }  
  466.             event.setAction(oldAction);  
  467.             return handled;  
  468.         }  
  469.   
  470.         // Calculate the number of pointers to deliver.  
  471.         final int oldPointerIdBits = event.getPointerIdBits();  
  472.         final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;  
  473.   
  474.         // If for some reason we ended up in an inconsistent state where it looks like we  
  475.         // might produce a motion event with no pointers in it, then drop the event.  
  476.         if (newPointerIdBits == 0) {  
  477.             return false;  
  478.         }  
  479.   
  480.         // If the number of pointers is the same and we don’t need to perform any fancy  
  481.         // irreversible transformations, then we can reuse the motion event for this  
  482.         // dispatch as long as we are careful to revert any changes we make.  
  483.         // Otherwise we need to make a copy.  
  484.         final MotionEvent transformedEvent;  
  485.         if (newPointerIdBits == oldPointerIdBits) {  
  486.             if (child == null || child.hasIdentityMatrix()) {  
  487.                 if (child == null) {  
  488.                     //调用自身的dispatchTouchEvent()!!!!!!  
  489.                     handled = super.dispatchTouchEvent(event);  
  490.                 } else {  
  491.                     final float offsetX = mScrollX - child.mLeft;  
  492.                     final float offsetY = mScrollY - child.mTop;  
  493.                     event.offsetLocation(offsetX, offsetY);  
  494.                     //调用子View的dispatchTouchEvent()!!!!!!  
  495.                     handled = child.dispatchTouchEvent(event);  
  496.                     event.offsetLocation(-offsetX, -offsetY);  
  497.                 }  
  498.                 return handled;  
  499.             }  
  500.             transformedEvent = MotionEvent.obtain(event);  
  501.         } else {  
  502.             transformedEvent = event.split(newPointerIdBits);  
  503.         }  
  504.   
  505.         // Perform any necessary transformations and dispatch.  
  506.         if (child == null) {  
  507.             handled = super.dispatchTouchEvent(transformedEvent);  
  508.         } else {  
  509.             final float offsetX = mScrollX - child.mLeft;  
  510.             final float offsetY = mScrollY - child.mTop;  
  511.             transformedEvent.offsetLocation(offsetX, offsetY);  
  512.             if (! child.hasIdentityMatrix()) {  
  513.                 transformedEvent.transform(child.getInverseMatrix());  
  514.             }  
  515.   
  516.             handled = child.dispatchTouchEvent(transformedEvent);  
  517.         }  
  518.   
  519.         transformedEvent.recycle();  
  520.         return handled;  
  521.     }  
  522.   //===============以上为dispatchTransformedTouchEvent()源码分析=================  
  523.   
  524. }  
package cc.aa;

import android.os.Environment;
import android.view.MotionEvent;
import android.view.View;

public class UnderstandDispatchTouchEvent {
    /**
     * 该示例的重点:
     * 1 ViewGroup的dispatchTouchEvent()源码学习及其注释
     * 2 ViewGroup的dispatchTransformedTouchEvent()源码学习及其注释
     * 3 弄明白两个问题:
     *   (1)为什么某个子View对于ACTION_DOWN返回false,那么系统不会讲ACTION_MOVE和ACTION_UP派发给该子View.
     *   因为ACTION_DOWN是一系列Touch事件的开端,如果子View对于该ACTION_DOWN事件在onTouchEvent()中返回了false即未消费.
     *   那么ViewGroup就不会把后续的ACTION_MOVE和ACTION_UP派发给该子View.在这种情况下ViewGroup就和普通的View一样了,
     *   调用该ViewGroup自己的dispatchTouchEvent()从而调用自己的onTouchEvent();即不会将事件分发给子View.
     *   详细代码请参见如下代码分析.
     *   
     *   (2)为什么子view对于Touch事件处理返回true那么其上层的ViewGroup就无法处理Touch事件了
     *   这个想必大家都知道了,因为该Touch事件被子View消费了其上层的ViewGroup就无法处理该Touch事件了.
     *   那么在源码中的依据是什么呢?请看下面的源码分析
     *   
     * 
     * 常说事件传递中的流程是:
     * dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent
     * 在这个链条中dispatchTouchEvent()是处在链首的位置当然也是最重要的.
     * 在dispatchTouchEvent()决定了Touch事件是由自己的onTouchEvent()处理
     * 还是分发给子View处理让子View调用其自身的dispatchTouchEvent()处理.
     * 
     * 
     * 其实dispatchTouchEvent()和onInterceptTouchEvent()以及onTouchEvent()的关系
     * 在dispatchTouchEvent()方法的源码中体现得很明显.
     * 比如dispatchTouchEvent()会调用onInterceptTouchEvent()来判断是否要拦截.
     * 比如dispatchTouchEvent()会调用dispatchTransformedTouchEvent()方法且在该方法中递归调用
     * dispatchTouchEvent();从而会在dispatchTouchEvent()里最终调用到onTouchEvent()
     * 
     * 
     * 
     *   
     * 参考资料:
     * 0 http://blog.csdn.net/sahadev_/article/details/23839039
     * 1 http://wangkuiwu.github.io/2015/01/04/TouchEvent-ViewGroup/
     * 2 http://www.cnblogs.com/xiaoweiz/p/3838682.html
     * 3 http://hukai.me/android-deeper-touch-event-dispatch-process/
     * 4 http://blog.csdn.net/yanbober/article/details/45912661
     * 5 http://www.eoeandroid.com/thread-542296-1-1.html
     * 6 http://www.eoeandroid.com/forum.php?mod=viewthread&tid=319301
     * 7 http://stackvoid.com/details-dispatch-onTouch-Event-in-Android/
     *   Thank you very much
     */

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
        }

        boolean handled = false;
        if (onFilterTouchEventForSecurity(ev)) {
            final int action = ev.getAction();
            final int actionMasked = action & MotionEvent.ACTION_MASK;

            /**
             * 第一步:对于ACTION_DOWN进行处理(Handle an initial down)
             * 因为ACTION_DOWN是一系列事件的开端,当是ACTION_DOWN时进行一些初始化操作.
             * 从源码的注释也可以看出来:清除以往的Touch状态(state)开始新的手势(gesture)
             * cancelAndClearTouchTargets(ev)中有一个非常重要的操作:
             * 将mFirstTouchTarget设置为null!!!!
             * 随后在resetTouchState()中重置Touch状态标识
             */
            if (actionMasked == MotionEvent.ACTION_DOWN) {
                // Throw away all previous state when starting a new touch gesture.
                // The framework may have dropped the up or cancel event for the previous gesture
                // due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }


            /**
             * 第二步:检查是否要拦截(Check for interception)
             * 在哪些情况下会调用该代码呢?有如下几种情况
             * 1 处理ACTION_DOWN事件
             * 2 当ACTION_DOWN事件被子View消费后处理ACTION_MOVE和ACTION_UP时
             *  会调用该代码。因为此时mFirstTouchTarget!=null。所以此时ViewGroup
             *  是有机会拦截ACTION_MOVE和ACTION_UP的,但是我们也可以调用方法:
             *  requestDisallowInterceptTouchEvent来禁止ViewGroup的事件拦截.
             *  如果子View没有消费Touch事件,那么那么当后续的ACTION_MOVE和ACTION_UP
             *  到来时是不会调用到本处代码的.
             *  
             * 在dispatchTouchEvent(MotionEventev)这一大段代码中
             * 使用变量intercepted来标记ViewGroup是否拦截Touch事件的传递.
             * 该变量在后续代码中起着很重要的作用.
             * 
             * 从此处if(actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null)及其内部代码可知:
             * 当ViewGroup决定拦截事件后,那么后续的点击事件将会默认交给它处理,不再调用
             * onInterceptTouchEvent()判断是否需要拦截.
             * 这个是为什么?
             * 因为在处理ACTION_DOWN时如果Touch事件被子View消费,那么mFirstTouchTarget不为空;
             * 反之,如果Touch事件没有被子View消费,那么mFirstTouchTarget为空,即此时Touch由当前
             * 的ViewGroup拦截。此时当ACTION_MOVE和ACTION_UP来到时,不再满足:
             * if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null)
             * 当然也就无法调用其内部的onInterceptTouchEvent()。
             * 通俗地说:一旦ViewGroup拦截了ACTION_DOWN事件由自身的onTouchEvent()处理,那么
             * 对于后续的ACTION_MOVE和ACTION_UP而言ViewGroup不再调用onInterceptTouchEvent()
             * 判断是否拦截.
             * 
             * 这里有个东西需要注意:FLAG_DISALLOW_INTERCEPT
             * 在子View中调用requestDisallowInterceptTouchEvent()后造成disallowIntercept为true
             * 即禁止拦截.于是不满足if(!disallowIntercept)所以也就调用不到该if内的onInterceptTouchEvent()
             * 自然就没有办法拦截了.
             * 但是requestDisallowInterceptTouchEvent()对于ACTION_DOWN是无效的.
             * 因为对于ACTION_DOWN会调用 cancelAndClearTouchTargets(ev)和resetTouchState();
             * 对FLAG_DISALLOW_INTERCEPT等状态值复原重置(参考上面的代码)
             * 
             * 举两种情况说明:
             * 1 当处理ACTION_DOWN时当然会满足
             *  if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null)
             *  对于ACTION_DOWN子View有两种处理结果
             *  1.1 消耗了Touch事件,那么mFirstTouchTarget不为null.
             *      所以处理后续的ACTION_MOVE和ACTION_UP时依然满足该if判断
             *  1.2 没有消耗Touch事件.mFirstTouchTarget=null.不满足该if.
             *      所以后续的ACTION_MOVE和ACTION_UP由ViewGroup处理,此时再讨论什么拦截也就没有意义了.
             *      同样的道理当子View消费了ACTION_DOWN后当处理ACTION_MOVE的时候ViewGroup拦截了该事件
             *      那么当ACTION_UP随之到来时由于mFirstTouchTarget=null所以不会再调用该段代码,自然也就
             *      不会调用onInterceptTouchEvent()判断是否拦截了.这点在上面的注释也有提及
             * 2 当出现1.1的情况时满足该if判断.
             *  如果在子View中调用了requestDisallowInterceptTouchEvent()那么就禁止拦截
             *  即disallowIntercept=true.所以不满足if (!disallowIntercept)当然也就调用不到
             *  onInterceptTouchEvent(ev)了,而是执行else{ intercepted = false;}
             *  也就是说ViewGroup无法拦截Touch了.
             */
            final boolean intercepted;
            // 事件为ACTION_DOWN或者mFirstTouchTarget不为null(即已经找到能够接收touch事件的目标组件)时if成立
            if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
                //判断disallowIntercept(禁止拦截)标志位
                //因为在其他地方可能调用了requestDisallowInterceptTouchEvent()改变该值.
                //对于此方法的作用其实看requestDisallowInterceptTouchEvent()这个方法名就可明白了
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                //当禁止拦截为false时(即disallowIntercept为false)调用onInterceptTouchEvent(ev)方法
                if (!disallowIntercept) {
                    //既然disallowIntercept为false那么就调用onInterceptTouchEvent()方法将结果赋值给intercepted
                    //常说事件传递中的流程是:dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent
                    //其实在这就是一个体现,在dispatchTouchEvent()中调用了onInterceptTouchEvent()
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    //禁止拦截的FLAG为ture说明没有必要去执行是否需要拦截了能够顺利通过,所以设置拦截变量为false
                    //即当禁止拦截为true时(即disallowIntercept为true)设置intercepted = false
                    intercepted = false;
                }
            } else {
                //当事件不是ACTION_DOWN并且mFirstTouchTarget为null(即没有Touch的目标组件)时
                //设置 intercepted = true表示ViewGroup执行Touch事件拦截的操作。
                //There are no touch targets and this action is not an initial down
                //so this view group continues to intercept touches.
                intercepted = true;
            }


            /**
             * 第三步:检查cancel(Check for cancelation)
             * 
             */
            final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;


            /**
             * 第四步:事件分发(Update list of touch targets for pointer down, if needed)
             */
            final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
            TouchTarget newTouchTarget = null;
            boolean alreadyDispatchedToNewTouchTarget = false;
            //不是ACTION_CANCEL并且ViewGroup的拦截标志位intercepted为false(不拦截)
            if (!canceled && !intercepted) {
                //处理ACTION_DOWN事件.这个环节比较繁琐.
                if (actionMasked == MotionEvent.ACTION_DOWN
                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                    final int actionIndex = ev.getActionIndex(); // always 0 for down
                    final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex):TouchTarget.ALL_POINTER_IDS;

                    // Clean up earlier touch targets for this pointer id in case they
                    // have become out of sync.
                    removePointersFromTouchTargets(idBitsToAssign);

                    final int childrenCount = mChildrenCount;
                    if (childrenCount != 0) {
                        // 依据Touch坐标寻找子View来接收Touch事件
                        // Find a child that can receive the event.
                        // Scan children from front to back.
                        final View[] children = mChildren;
                        final float x = ev.getX(actionIndex);
                        final float y = ev.getY(actionIndex);

                        final boolean customOrder = isChildrenDrawingOrderEnabled();
                        // 遍历子View判断哪个子View接受Touch事件
                        for (int i = childrenCount - 1; i >= 0; i--) {
                            final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
                            final View child = children[childIndex];
                            if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) {
                                continue;
                            }

                            newTouchTarget = getTouchTarget(child);
                            if (newTouchTarget != null) {
                                // 找到接收Touch事件的子View!!!!!!!即为newTouchTarget.
                                // 既然已经找到了,所以执行break跳出for循环
                                // Child is already receiving touch within its bounds.
                                // Give it the new pointer in addition to the ones it is handling.
                                newTouchTarget.pointerIdBits |= idBitsToAssign;
                                break;
                            }

                            resetCancelNextUpFlag(child);
                            /**
                             * 如果上面的if不满足,当然也不会执行break语句.
                             * 于是代码会执行到这里来.
                             * 
                             * 
                             * 调用方法dispatchTransformedTouchEvent()将Touch事件传递给子View做
                             * 递归处理(也就是遍历该子View的View树)
                             * 该方法很重要,看一下源码中关于该方法的描述:
                             * Transforms a motion event into the coordinate space of a particular child view,
                             * filters out irrelevant pointer ids, and overrides its action if necessary.
                             * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
                             * 将Touch事件传递给特定的子View.
                             * 该方法十分重要!!!!!!!!!!!!!!!!!
                             * 在该方法中为一个递归调用,会递归调用dispatchTouchEvent()方法!!!!!!!!!!
                             * 在dispatchTouchEvent()中:
                             * 如果子View为ViewGroup并且Touch没有被拦截那么递归调用dispatchTouchEvent()
                             * 如果子View为View那么就会调用其onTouchEvent(),这个不再赘述.
                             * 
                             * 
                             * 该方法返回true则表示子View消费掉该事件,同时进入该if判断.
                             * 满足if语句后重要的操作有:
                             * 1 给newTouchTarget赋值
                             * 2 给alreadyDispatchedToNewTouchTarget赋值为true.
                             *   看这个比较长的英语名字也可知其含义:已经将Touch派发给新的TouchTarget
                             * 3 执行break.
                             *   因为该for循环遍历子View判断哪个子View接受Touch事件,既然已经找到了
                             *   那么就跳出该for循环.
                             * 4 注意:
                             *   如果dispatchTransformedTouchEvent()返回false即子View的onTouchEvent返回false
                             *   (即Touch事件未被消费)那么就不满足该if条件.所以也就无法执行addTouchTarget().
                             *   在此简单说一下addTouchTarget()中涉及到的ViewGroup的一个内部类TouchTarget——它是一个事件链.
                             *   该处的mFirstTouchTarget就是一个TouchTarget.它保存了可以消耗Touch事件的View.
                             *   在该处,如果dispatchTransformedTouchEvent()返回true即子View的onTouchEvent返回true则说明
                             *   该View消耗了Touch事件,那么将该View加入到事件链中!!!!!!!!!!!!!!!
                             *   尤其注意:
                             *   这个操作是在处理ACTION_DOWN的代码块里进行的.即是在:
                             *    if (actionMasked == MotionEvent.ACTION_DOWN|| 
                             *    (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || 
                             *    actionMasked == MotionEvent.ACTION_HOVER_MOVE)
                             *    这个大的if判断中处理的.
                             *    当处理ACTION_MOVE事件和ACTION_UP事件的时候是不会进入这个if判断的!!!!!
                             *    而是直接从去判断mFirstTouchTarget!!!!!!!!!!!!!!!!
                             *    所以如果一个View不处理ACTION_DOWN那么该,那么该View是不会保存在mFirstTouchTarget
                             *    中的,也就无法继续处理ACTION_MOVE事件和ACTION_UP事件!!!!!!!!!!即若该View不消耗
                             *    ACTION_DOWN事件那么系统是不会讲ACTION_MOVE和ACTION_UP事件传给给该View的
                             * 5 注意:
                             *   如果dispatchTransformedTouchEvent()返回true即子View
                             *   的onTouchEvent返回true(即Touch事件被消费)那么就满足该if条件.
                             *   从而mFirstTouchTarget不为null!!!!!!!!!!!!!!!!!!!
                             * 6 小结:
                             *   对于此处ACTION_DOWN的处理具体体现在dispatchTransformedTouchEvent()
                             *   该方法返回boolean,如下:
                             *   true---->事件被消费----->mFirstTouchTarget!=null
                             *   false--->事件未被消费--->mFirstTouchTarget==null
                             *   因为在dispatchTransformedTouchEvent()会调用递归调用dispatchTouchEvent()和onTouchEvent()
                             *   所以dispatchTransformedTouchEvent()的返回值实际上是由onTouchEvent()决定的.
                             *   
                             *   简单地说onTouchEvent()是否消费了Touch事件(true or false)的返回值决定了
                             *   dispatchTransformedTouchEvent()的返回值!!!!从而决定了mFirstTouchTarget是否为null!!!!!!
                             *   从而进一步决定了ViewGroup是否处理Touch事件.这一点在下面的代码中很有体现.
                             */
                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                // Child wants to receive touch within its bounds.
                                mLastTouchDownTime = ev.getDownTime();
                                mLastTouchDownIndex = childIndex;
                                mLastTouchDownX = ev.getX();
                                mLastTouchDownY = ev.getY();
                                //调用addTouchTarget()将child添加到mFirstTouchTarget链表的表头
                                //注意在addTouchTarget()方法内部会对mFirstTouchTarget操作,使其不为null
                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
                                alreadyDispatchedToNewTouchTarget = true;
                                break;
                            }
                        }//for循环结束
                    }


                    /**
                     * 该if条件表示:
                     * 经过前面的for循环没有找到子View接收Touch事件并且之前的mFirstTouchTarget不为空
                     */
                    if (newTouchTarget == null && mFirstTouchTarget != null) {
                        // Did not find a child to receive the event.
                        // Assign the pointer to the least recently added target.
                        newTouchTarget = mFirstTouchTarget;
                        while (newTouchTarget.next != null) {
                            newTouchTarget = newTouchTarget.next;
                        }
                        //newTouchTarget指向了最初的TouchTarget
                        newTouchTarget.pointerIdBits |= idBitsToAssign;
                    }//处理ACTION_DOWN结束
                }
            }



            /**
             * 经过上面对于ACTION_DOWN的处理后mFirstTouchTarget有两种情况:
             * (当然如果不是ACTION_DOWN就不会经过上面较繁琐的流程而是从此处开始执行,比如ACTION_MOVE和ACTION_UP)
             * 
             * 情况1 mFirstTouchTarget为null
             *       即没有找到能够消费touch事件的子组件或者是touch事件被拦截了
             * 情况2 mFirstTouchTarget不为null
             *       即找到了能够消费touch事件的子组件则后续的touch事件都可以传递到子View
             * 这两种情况的详细分析见下.
             * 
             * 这两种情况下都会去调用方法:
             * dispatchTransformedTouchEvent(MotionEvent event,boolean cancel,View child,int desiredPointerIdBits)
             * 我们重点关注该方法的第三个参数View child.
             * 详情请参加下面dispatchTransformedTouchEvent()源码分析
             * 在该源码中解释了:
             * 为什么子view对于Touch事件处理返回true那么其上层的ViewGroup就无法处理Touch事件了!!!!!!!!!
             * 为什么子view对于Touch事件处理返回false那么其上层的ViewGroup才可以处理Touch事件!!!!!!!!!!
             * 
             */
            if (mFirstTouchTarget == null) {
                /**
                 * 情况1:mFirstTouchTarget为null
                 * 
                 * 经过上面的分析mFirstTouchTarget为null就是说Touch事件未被消费.
                 * 即没有找到能够消费touch事件的子组件或Touch事件被拦截了,
                 * 则调用ViewGroup的dispatchTransformedTouchEvent()方法处理Touch事件则和普通View一样.
                 * 即子View没有消费Touch事件,那么子View的上层ViewGroup才会调用其onTouchEvent()处理Touch事件.
                 * 在源码中的注释为:No touch targets so treat this as an ordinary view.
                 * 也就是说此时ViewGroup像一个普通的View那样调用dispatchTouchEvent(),且在dispatchTouchEvent()
                 * 中会去调用onTouchEvent()方法.
                 * 具体的说就是在调用dispatchTransformedTouchEvent()时第三个参数为null.
                 * 第三个参数View child为null会做什么样的处理呢?
                 * 请参见下面dispatchTransformedTouchEvent()的源码分析
                 */
                handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);
            } else {
                /**
                 * 情况2:mFirstTouchTarget不为null
                 * 即找到了可以消费Touch事件的子View且后续Touch事件可以传递到该子View
                 * 在源码中的注释为:
                 * Dispatch to touch targets, excluding the new touch target if we already dispatched to it.  
                 * Cancel touch targets if necessary.
                 */
                TouchTarget predecessor = null;
                TouchTarget target = mFirstTouchTarget;
                while (target != null) {
                    final TouchTarget next = target.next;
                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                        //如果前面利用ACTION_DOWN事件寻找符合接收条件的子组件的同时消费掉了ACTION_DOWN事件
                        //那么这里为handled赋值为true
                        handled = true;
                    } else {
                        final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;
                        //对于非ACTION_DOWN事件继续传递给目标子组件进行处理
                        //依然是递归调用dispatchTransformedTouchEvent()
                        if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) {
                            handled = true;
                        }
                        if (cancelChild) {
                            if (predecessor == null) {
                                mFirstTouchTarget = next;
                            } else {
                                predecessor.next = next;
                            }
                            target.recycle();
                            target = next;
                            continue;
                        }
                    }
                    predecessor = target;
                    target = next;
                }
            }

            /**
             * 处理ACTION_UP和ACTION_CANCEL
             * Update list of touch targets for pointer up or cancel, if needed.
             * 在此主要的操作是还原状态
             */
            if (canceled|| actionMasked == MotionEvent.ACTION_UP
                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                resetTouchState();
            } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
                final int actionIndex = ev.getActionIndex();
                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
                removePointersFromTouchTargets(idBitsToRemove);
            }
        }

        if (!handled && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
        }
        return handled;
    }



    //=====================以上为dispatchTouchEvent()源码分析======================







    //===============以下为dispatchTransformedTouchEvent()源码分析=================

    /**
     * 在dispatchTouchEvent()中会调用dispatchTransformedTouchEvent()将事件分发给子View处理
     * 
     * Transforms a motion event into the coordinate space of a particular child view,
     * filters out irrelevant pointer ids, and overrides its action if necessary.
     * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
     * 
     * 在此请着重注意第三个参数:View child
     * 在dispatchTouchEvent()中多次调用dispatchTransformedTouchEvent(),但是有时候第三个参数为null,有时又不是.
     * 那么这个参数是否为null有什么区别呢?
     * 在如下dispatchTransformedTouchEvent()源码中可见多次对于child是否为null的判断,并且均做出如下类似的操作:
     * if (child == null) {
     *       handled = super.dispatchTouchEvent(event);
     *    } else {
     *       handled = child.dispatchTouchEvent(event);
     * }
     * 这个代码是什么意思呢?
     * 
     * 当child == null时会将Touch事件传递给该ViewGroup自身的dispatchTouchEvent()处理.
     * 即super.dispatchTouchEvent(event)
     * 正如源码中的注释描述的一样:
     * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
     * 
     * 当child != null时会调用该子view(当然该view可能是一个View也可能是一个ViewGroup)的dispatchTouchEvent(event)处理.
     * 即child.dispatchTouchEvent(event);
     * 
     * 那么该child是否为null又是由什么决定的呢?
     * 在dispatchTouchEvent()中已经知道了:
     * 如果Touch事件被消耗掉那么child不为null
     * 如果Touch事件未被消耗掉那么child为null
     * 
     * 这就解释了:
     * 为什么子view对于Touch事件处理返回true那么其上层的ViewGroup就无法处理Touch事件了!!!!!!!!!
     * 为什么子view对于Touch事件处理返回false那么其上层的ViewGroup才可以处理Touch事件!!!!!!!!!!
     */
    private boolean dispatchTransformedTouchEvent(MotionEvent event,boolean cancel,View child,int desiredPointerIdBits) {
        final boolean handled;
        // Canceling motions is a special case.  We don't need to perform any transformations
        // or filtering.  The important part is the action, not the contents.
        final int oldAction = event.getAction();
        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }

        // Calculate the number of pointers to deliver.
        final int oldPointerIdBits = event.getPointerIdBits();
        final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;

        // If for some reason we ended up in an inconsistent state where it looks like we
        // might produce a motion event with no pointers in it, then drop the event.
        if (newPointerIdBits == 0) {
            return false;
        }

        // If the number of pointers is the same and we don't need to perform any fancy
        // irreversible transformations, then we can reuse the motion event for this
        // dispatch as long as we are careful to revert any changes we make.
        // Otherwise we need to make a copy.
        final MotionEvent transformedEvent;
        if (newPointerIdBits == oldPointerIdBits) {
            if (child == null || child.hasIdentityMatrix()) {
                if (child == null) {
                    //调用自身的dispatchTouchEvent()!!!!!!
                    handled = super.dispatchTouchEvent(event);
                } else {
                    final float offsetX = mScrollX - child.mLeft;
                    final float offsetY = mScrollY - child.mTop;
                    event.offsetLocation(offsetX, offsetY);
                    //调用子View的dispatchTouchEvent()!!!!!!
                    handled = child.dispatchTouchEvent(event);
                    event.offsetLocation(-offsetX, -offsetY);
                }
                return handled;
            }
            transformedEvent = MotionEvent.obtain(event);
        } else {
            transformedEvent = event.split(newPointerIdBits);
        }

        // 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);
        }

        transformedEvent.recycle();
        return handled;
    }
  //===============以上为dispatchTransformedTouchEvent()源码分析=================

}

            </div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值