dispatchTouchEvent源码解析

来源:互联网 发布:持有期收益率知乎 编辑:程序博客网 时间:2024/06/06 00:09

1. dispatchTouchEvent是处理触摸事件分发,Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件没有被消费。返回false则继续往下分发,如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件,事件(多数情况)是从Activity的dispatchTouchEvent开始的。执行dispatchTouchEvent(ev),事件向下分发。


2. onInterceptTouchEvent是ViewGroup中才有的方法,View中没有,它的作用是负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在Android中View中是不能再包含子View的(iOS可以)


3. onTouchEvent是View中提供的方法,ViewGroup也有这个方法,view中不提供onInterceptTouchEvent。view中默认返回true,表示消费了这个事件,onTouchEvent方法用于事件的处理,返回true表示消费处理当前事件,返回false则不处理,交给子控件进行继续分发。

 

知识点:

1.Android中事件传递按照从上到下进行层级传递,事件处理从Activity开始到ViewGroup再到View。


2.事件传递方法包括dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent,其中前两个是View和ViewGroup都有的,最后一个是只有ViewGroup才有的方法。这三个方法的作用分别是负责事件分发、事件处理、事件拦截。


3.onTouch事件要先于onClick事件执行,onTouch在事件分发方法dispatchTouchEvent中调用,而onClick在事件处理方法onTouchEvent中被调用,onTouchEvent要后于dispatchTouchEvent方法的调用。


代码分析:

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


参考资料:

Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()

Android事件传递机制

源码解析
0 0