android 事件分发机制(源码分析)—(详细)(逐步总结)(值得一看)

核心方法:

ONEdispatchTouchEvent(MotionEvent ev)处理整个事件的核心所在,事件分发由它执行,重要到什么程度

如果你自定义一个Layout并且重写这个方法将其代码清空那么这个ViewGroup以及它的所有子View将都无法接收任何事件

TWOonInterceptTouchEvent(MotionEvent ev)用于事件的拦截,就是决定这个事件是否继续传递(见本文),

既然传递就联系到ViewGroup与View,而android本身的规则,事件由顶向外层传递,也就是ViewGroup向View

传递, 而View并没有子View,也就是说View的控件是没有这个方法的。当然我们可以决定是否往下继续传递。

THEREonTouchEvent(MotionEvent event)这个都很熟悉了,代码写在里面可以响应触摸事件(见本文)。


第一步对屏幕产生一个触摸事件, 这个事件被包装成MotionEvent对象

第二步这个对象被发送到Activity,并且调ActivitydispatchTouchEvent:看源码:

public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();        //内部为空方法。
    }
    if (getWindow().superDispatchTouchEvent(ev)) {    //核心所在
        return true;     
    }
    return onTouchEvent(ev);
}

   上述代码的核心就是调用了getWindow().superDispatchTouchEvent(ev) 而Windows是一个抽象类,具体的实现为PhoneWindow

 所以看PhoneWindows的此方法:

    public boolean superDispatchTouchEvent(MotionEvent event) {
       return mDecor.superDispatchTouchEvent(event);
    }     
	mDecor应该都很熟悉吧,做最顶层的View它本身就是个FrameLayout,我们DecorView点进去最后来到了ViewGroup里并且调用了
dispatchTouchEvent(MotionEvent ev)方法。
    所以上述过程总结: 触摸屏幕 产生一个MotionEvent对象,该对象包含触摸的相关信息,而这个对象经过Activity转到DecorView再到根ViewGroup。
所以一切的开端都是ViewGroupdispatchTouchEvent(MotionEvent ev)。 
 
public boolean dispatchTouchEvent(MotionEvent ev) {
 
 
if (onFilterTouchEventForSecurity(ev)) {
    final int action = ev.getAction();
    final int actionMasked = action & MotionEvent.ACTION_MASK;
    if (actionMasked == MotionEvent.ACTION_DOWN) {       //判断是否为DOWN事件。
        resetTouchState();     //初始化操作核心代码
    }
	//只添加了我们步骤的核心代码, 
}  
 第三步判断这个事件是否为DOWN事件并且做一些初始化操作,因为触摸屏幕总是以Down开始UP结束。看源码:
private void resetTouchState() {
    clearTouchTargets();     // 核心代码
}   接着看:
private void clearTouchTargets() {
    TouchTarget target = mFirstTouchTarget;    
    if (target != null) {
        do {
            TouchTarget next = target.next;
            target.recycle();       //回收这个对象
            target = next;
        } while (target != null);
        mFirstTouchTarget = null;        //核心,将其置空
    }
}
  上述的mFirstTouchTarget对象才是我们所要看到的,初始化就是让mFristTouchTarget=null
 请注意:一定是Down事件时才会初始化,否则会保留上一次的mFristTouchTarget.
  mFirstTouchTarget又是什么呢? 继续看源码:
private static final class TouchTarget {
    private static TouchTarget sRecycleBin;
    private static int sRecycledCount;
    public View child;     
    public TouchTarget next;
 	//截取现需的
}
    ViewGroup的内部类,这个类包含一个VIew以及本身,  这个View是什么? 当我们触摸的那个View如果消耗了这个
 事件那么这个View就会标记那个View,next一般标记为null,我们注意这个View就行。ok mFirstTouchTarget=null后
第三步也就完成了。
 第四步回到dispatchTouchEvent里继续往下看代码
public boolean dispatchTouchEvent(MotionEvent ev) {
 
 
if (actionMasked == MotionEvent.ACTION_DOWN
        || mFirstTouchTarget != null) {      
    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    if (!disallowIntercept) {
        intercepted = onInterceptTouchEvent(ev);
        ev.setAction(action); // restore action in case it was changed
    } else {
        intercepted = false;        // 核心,标志着是否拦截
    }
} else {
    intercepted = true;
 }
}
	上述代码就是接着初始化后进行的,其实就是判断是否拦截。intercepted=true表示拦截,
拦截不拦截其实就是dispatchTouchEvent里的部分代码执行或不执行。
先看看:
if (actionMasked == MotionEvent.ACTION_DOWN
        || mFirstTouchTarget != null)  如果是一个down事件或者非down事件但是mFristTouchTarget
已经不是初始化时的值时会执行。  那么mFristTouchTarget什么时候会为非初始化值呢,  为了方便理解,笔者提前说下
后面会用源码证实。  mFristTouchTarget只有在这个ViewGroupchild消耗了这个事件的时候才会不为null。
要注意的是一切都从DeCorView开始
满足条件后又做了什么呢?  接着看:
 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 
disallowIntercept作用是过滤, 如果是down事件值为false,非down事件值为true。也就是说down事件才会继续执行:
 if (!disallowIntercept) {
        intercepted = onInterceptTouchEvent(ev);
        ev.setAction(action); // restore action in case it was changed
    }		在这里调用了onInterceptTouchEvent(ev); 根据返回值判断是否拦截事件。也就是说只有down事件才会调用决定是否拦截的代码。
               如果为非down事件则直接为intercepted = false  不拦截; 
 
 
 
 
而 if (actionMasked == MotionEvent.ACTION_DOWN
        || mFirstTouchTarget != null) {   
为false时会执行   
else {
    intercepted = true;
 }
    也就是说非down事件,并且child没有消耗这个事件时会拦截。
 
 
将上述总结一下:一个触摸事件对其判定有两种:
		ONE: Down事件,直接调用onInterceptTouchEvent(ev)决定是否拦截
		TWO非Down事件,如果这个非Down事件的起始事件(Down事件)没有拦截,
		     并且后续操作中消耗了这个事件,那么这个非Down事件就不会拦截。		    
 
 
 
 
                     如果这个非Down事件的起始事件(Down事件)没有拦截,
		     但是后续操作中并没有消耗这个事件,那么这个非Down事件就会拦截,
如果这个非Down事件的起始事件(Down事件)拦截了,
		     那么这个非Down事件就会被拦截。 
第五步拦截与不拦截会有那些不同呢?
public boolean dispatchTouchEvent(MotionEvent ev) {	
     TouchTarget newTouchTarget = null;
     boolean alreadyDispatchedToNewTouchTarget = false;
 
if (!canceled && !intercepted) {            
 
 
  for (int i = childrenCount - 1; i >= 0; i--) {      
    final int childIndex = getAndVerifyPreorderedIndex(
            childrenCount, i, customOrder);
    final View child = getAndVerifyPreorderedView(
            preorderedList, children, childIndex);
    if (childWithAccessibilityFocus != null) {
        if (childWithAccessibilityFocus != child) {
            continue;
        }
        childWithAccessibilityFocus = null;
        i = childrenCount - 1;
    }

    if (!canViewReceivePointerEvents(child)
            || !isTransformedTouchPointInView(x, y, child, null)) {
        ev.setTargetAccessibilityFocus(false);
        continue;
    }
    newTouchTarget = getTouchTarget(child);
    if (newTouchTarget != null) {
        newTouchTarget.pointerIdBits |= idBitsToAssign;
        break;
    }
    resetCancelNextUpFlag(child);
    if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
        mLastTouchDownTime = ev.getDownTime();
        if (preorderedList != null) {
            for (int j = 0; j < childrenCount; j++) {
                if (children[childIndex] == mChildren[j]) {
                    mLastTouchDownIndex = j;
                    break;
                }
            }
        } else {
            mLastTouchDownIndex = childIndex;
        }
        mLastTouchDownX = ev.getX();
        mLastTouchDownY = ev.getY();
        newTouchTarget = addTouchTarget(child, idBitsToAssign);
        alreadyDispatchedToNewTouchTarget = true;
        break;
    }
    ev.setTargetAccessibilityFocus(false);
}
         }			//上述代码均在循环结构里
 
 
	这一步骤大致看到的是遍历子View,那么前提肯定是不拦截了:
   if (!canceled && !intercepted) {   //如果intercepted=false则执行。
   接着分析:
for (int i = childrenCount - 1; i >= 0; i--) {      
    final int childIndex = getAndVerifyPreorderedIndex(
            childrenCount, i, customOrder);
    final View child = getAndVerifyPreorderedView(
            preorderedList, children, childIndex);
    if (childWithAccessibilityFocus != null) {
        if (childWithAccessibilityFocus != child) {
            continue;                       //跳出本次的Child对象
        }
        childWithAccessibilityFocus = null;
        i = childrenCount - 1;
    }

    if (!canViewReceivePointerEvents(child)
            || !isTransformedTouchPointInView(x, y, child, null)) {
        ev.setTargetAccessibilityFocus(false);
        continue;			   //跳出本次的Child对象	
    }
	上述我们看到了一个循环,然后进行筛选,不满足的就跳出当前。所以上述代码执行完后能剩下的肯定就是可以接受本次事件的:
  继续分析:	
  newTouchTarget = getTouchTarget(child);
    if (newTouchTarget != null) {
        newTouchTarget.pointerIdBits |= idBitsToAssign;
        break;
    }
第五步 刚开始就会调用TouchTarget newTouchTarget = null;
 也就是说newTouchTarget在循环前就会被置空,所以它只存活于一个事件的过程,我们知道mFristTouchTarget也属于TouchTarget类,
而上文我们说过mFristTouchTarget中有View用于存放消耗事件的View,那么接着看getTouchTarget(child)执行了那些操作:
  for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
      if (target.child == child) {
        return target;
    }
}
  return null;
	上述过程就是判断如果target!=null,也就是mFristTouchTarget!=null,也就是说存在消费事件的View,同理也能说明当前非Down事件时
如果循环得到的View与Down的View相同那就将这个mFristTouchTarget返回,因此newTouchTarget==mFristTouchTarget。
所以mFtistTouchTarget!=null  if (newTouchTarget != null) 成立 于是退出了循环,读者可能会疑惑为什么要这么做?这里留下一个问题X  继续看循环里源码:
 
 
for (int i = childrenCount - 1; i >= 0; i--) {
 
  
 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
 if (preorderedList != null) {
    // childIndex points into presorted list, find original index
    for (int j = 0; j < childrenCount; j++) {
        if (children[childIndex] == mChildren[j]) {
            mLastTouchDownIndex = j;
            break;
        }
    }
} else {
    mLastTouchDownIndex = childIndex;
}
   mLastTouchDownX = ev.getX();
   mLastTouchDownY = ev.getY();
   newTouchTarget = addTouchTarget(child, idBitsToAssign);
   alreadyDispatchedToNewTouchTarget = true;
     break;
 }
这一块是核心所在了,
dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)  
先说明一下,整个循环结构能到这一步就表示:ONE当前事件为Down事件,
				      TWO已经找到了合适的Child
	为什么说当前事件时Down事件, 因为能执行这个循环结构就表示事件未拦截,
  事件未拦截就有两种情况: 1: Down事件, 2:非Down事件且存在消耗事件的View, 为什么不会是情况2呢,
看看上面的这个:
 newTouchTarget = getTouchTarget(child);
    if (newTouchTarget != null) {
        newTouchTarget.pointerIdBits |= idBitsToAssign;
        break;
    }
我们知道newTouchTarget==mFristTouchTager 如果为非Down事件那么这些就会执行然后退出循环下面自然执行不到。
所以上面的问题X自然就清楚了,  就是防止这些代码的执行,那为什么要防止这些代码执行, Down执行了一次,而非Down就不让执行呢? 	
看里面代码:
for (int j = 0; j < childrenCount; j++) {
    if (children[childIndex] == mChildren[j]) {
        mLastTouchDownIndex = j;
        break;
    }
}
newTouchTarget = addTouchTarget(child, idBitsToAssign);  看addTouchTarget内部:
private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
    final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
    target.next = mFirstTouchTarget;
    mFirstTouchTarget = target;         //注意整个事件的过程只有在这里给mFristTouchTarget添加了对象。
    return target;
}
说明一下:TouchTarget.obtain  会创建一个TouchTarget将内部的View指向参数的Child,然后mFristTouchTarget=target,最后
newTouchTarget=target,所以newTouchTarget==mFristTouchTarget,  这些过程都发生在Down事件里,一定要记住mFristTouchTarget
只有在Down事件过程才有可能添加对象。
		所以上述问题为什么非Down不允许运行。因为没有必要多次执行耗时并且相同的动作。
细心的你可能又留意到了,一个问题的解决又产生了一个问题, 为什么说可能会添加对象。请注意:上述过程前提是
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign))  成立的情况下。那就看一看它的源码是什么:
    
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
        View child, int desiredPointerIdBits) {
  
   transformedEvent = MotionEvent.obtain(event);     //根据当前的event产生一个效果相同的MotionEvent
   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);
   }
       return handled;
}
解释 child为循环找到的view,ev为触摸事件, transforedEvent的效果与event相同(可能是为了防止某些东西被修改吧),
      然后进行了判断,
  if (child == null) {
       handled = super.dispatchTouchEvent(transformedEvent);         
       }else {
     handled = child.dispatchTouchEvent(transformedEvent);
 }	
   有两个问题1: 为什么child可以为null, 
		2:  super.dispatchTouchEvent与child.dispatchTouchEvent有何不同

	    问题1: 我们当前在循环里执行的方法传入的child确实不为null,但是在循环外部child却可以为null,所以child的不同引起了问题2。
	    问题2:这个问题有着至关重要的作用, 牢记:我们知道ViewGroup是继承View的所以super. dispatchTouchEvent就是View.dispatchTouchEvent
                   而ViewGroup又重写了View的dispatchTouchEvent方法,所以导致super.dispatchTouchEvent与ViewGroup.dispatchTouchEvent有差异,               
 
 
                  child.dispatchTouchEvent又是什么呢,我们知道child是这个ViewGroup的子类,是子类就会有两种情况:一个是View;一个是ViewGroup
                  所以child.dispatchTouchEvent介于两者之间。child是ViewGroup的话就会执行我们上述研究的dispatchTouchEvent方法。
			

  
下面进行第六步:我们来简短的分析一下super.dispatchTouchEvent源码:
 
 
public boolean dispatchTouchEvent(MotionEvent event) {
	
if (onFilterTouchEventForSecurity(event)) {
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnTouchListener != null
            && (mViewFlags & ENABLED_MASK) == ENABLED
            && li.mOnTouchListener.onTouch(this, event)) {
        result = true;
    }

    if (!result && onTouchEvent(event)) {
        result = true;
     }
   }
	return result;
}
我们重点关注这些代码, onFilterTouchEventForSecurity(event)是一种安全策略,一般为true。
 ListenerInfo li = mListenerInfo;   ListenerInfo是什么类呢?  点进去:
static class ListenerInfo {
 
 
  protected OnFocusChangeListener mOnFocusChangeListener;
  public OnClickListener mOnClickListener;
  protected OnLongClickListener mOnLongClickListener;
  private OnTouchListener mOnTouchListener;
...
}
可以看到ListenerInfo 是一个专门用于存放View的各种监听事件的类,
一般情况一个View都会有一个mListenerInfo。 看看一个重写的监听事件对象怎么存放进去:
public void setOnTouchListener(OnTouchListener l) {
    getListenerInfo().mOnTouchListener = l;
}
   getListenerinfo的源码:
 ListenerInfo getListenerInfo() {
    if (mListenerInfo != null) {
        return mListenerInfo;
    }
    mListenerInfo = new ListenerInfo();
    return mListenerInfo;
}
getListenerinfo拿到了当前View的mListenerInfo,然后将我们重写的对象放入mListenerInfo管理。回到上文:
li=mListenerInfo后li便可以执行监听事件操作了。接着分析:
if (li != null && li.mOnTouchListener != null
            && (mViewFlags & ENABLED_MASK) == ENABLED
            && li.mOnTouchListener.onTouch(this, event)) {
        result = true;
    }
上述可以看到我们的给View添加的onTouch()返回true时。 result就会返回true。
  记着这个结论:onTouch()返回true,result=true;这时候也就说明我们的onTouch()方法已经执行了。
    if (!result && onTouchEvent(event)) {
        result = true;
     } 
  这个是接着上述代码的, 如果result=true那么就不会执行,onTouchEvent()方法也就不会执行。
  所以onTouch()的优先级要高于onTouchEvent(),
 稍微总结一下:   OnTouch()的优先级要高于OnTouchEvent();
		OnTouch()返回值为true,onTouchEvent()不会执行。
	 
  ok 然后我们研究一下这个result, 这也是一个至关重要的存在,注意super.dispatchTouchEvent的返回值:
	return result;它是返回result的,千万别忽视super.dispatchTouchEvent或者child.dispatchTouchEvent返回值。
 我们仔细想一想前面我们代码中写过这个返回值返回给谁?      
              handled = super.dispatchTouchEvent(transformedEvent);
              handled = child.dispatchTouchEvent(transformedEvent);
    handled是哪个方法里面的?没错来自于   
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
        View child, int desiredPointerIdBits) {
return handled;
}
  这个方法最后返回的是handled, 也就是返回result, 那么返回给谁呢?  这时又回到了我们开始的地方
是不是在循环里面有过这样的代码:
  if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
      newTouchTarget = addTouchTarget(child, idBitsToAssign);   
      alreadyDispatchedToNewTouchTarget = true;
      break;
}
上面我们是不是说过这个步骤可能会给mFristTouchTarget添加对象,添加对象就是执行了这个:
     newTouchTarget = addTouchTarget(child, idBitsToAssign);  不够清楚的话再回到上面看看。
而决定是否添加mFristTouchTarget就是上述判断,也就是handled,result的值
也就是它child的OnTouch,OnTouchEvent的返回值。
      请注意这个child值的是离得当前View最近的child无论是View还是ViewGroup,
		打个比方, A里面有B,B里面有C,  那如果这个方法是在A里面的话child指的就是B。
 
 
 总结一下: 经过上述过程我们知道了,child的OnTouch()或者OnTouchEvent()返回值会直接影响调用它的dispatchTouchEvent()方法的Parent,
          具体怎么影响呢? 会使得Parent的mFristTouchTarget是否为null。  返回值为true 则mFristTouchTarget!=null。
	
	这里产生一个很重要的问题: mFristTouchTarget是否为null对整个事件分发有什么影响呢?  继续看循环外面的代码:
第七步
   if (mFirstTouchTarget == null) {
    handled = dispatchTransformedTouchEvent(ev, canceled, null,
            TouchTarget.ALL_POINTER_IDS);
} else {
  ......}
     可以看到在循环外部又判断了mFristTouchTarget为空, 
    handled = dispatchTransformedTouchEvent(ev, canceled, null,
            TouchTarget.ALL_POINTER_IDS);
 行了在循环内部一模一样的操作。	来回顾一下要执行循环内部dispatchTransformedTouchEvent()需要那些条件?
 
 
           整个循环结构能到这一步就表示:ONE当前事件为Down事件
				      TWO已经找到了合适的Child。
     
  这两个方法执行条件有什么不同呢?循环里的:child已经找到
				        事件为Down。
				这里的: mFristTouchTarget=null;
					onTouch()和onTouchEvent()都返回false      		   
请注意: 循环外的此方法由于child==null,所以最终会执行super.dispatchTouchEvent()
		也就是执行自己的onTouch()或者onTouchEvent();
		执行时期: Down事件{
		               A:拦截  
                               B:未拦截,child未消耗。	   
                                 }
			  非Down事件{
                       	         A:拦截	      
                                      }	
                循环里的此方法child!=null,所以会执行child.dispatchTouchEvent()
		所以最终会执行super.dispatchTouchEvent()或者ViewGroup.dispatchTouchTarget()
		完全取决于child是View还是ViewGroup, 若是ViewGroup则会执行我们从头开始分析的过程
		进而形成一种循环,直到当前拿到的事件被拦截,或者当前的child为View。
		执行时期: Down事件{
                               A:未拦截 
                                   }	
			  非Down事件{
                                 无法执行。   
                                }	
	         提醒这里的child指的是离当前最近的.
                      打个比方 A里有B,B里有C, A执行dispatchTouchEvent()会把事件传给B。同理

第八步
如果循环里的dispatchTransformedTouchEvent()执行时期是Down事件并且未拦截
	那么假如一个View消耗了Down事件,所以后续的非Down事件都要传给它,但是它已经无法接收了,那么后续的事件如何响应呢?
    
       接着看else{...}:
    TouchTarget predecessor = null;
    TouchTarget target = mFirstTouchTarget;
    while (target != null) {
        final TouchTarget next = target.next;
        if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
            handled = true;
        } else {
            final boolean cancelChild = resetCancelNextUpFlag(target.child)
                    || intercepted;
            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;
    }
}
   注意能调用else{..}已经表示child消耗了事件。  
 
 
  if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
            handled = true;
        } else {
            final boolean cancelChild = resetCancelNextUpFlag(target.child)
                    || intercepted;
            if (dispatchTransformedTouchEvent(ev, cancelChild,
                    target.child, target.pointerIdBits)) {
                handled = true;
            }
   无论是Down还是非Down ,只要事件被消耗那mFristTouchTarget!=null, newTouchTarget始终==mFristTouchTarget
   所以target==newTouchTarget成立, 然后注意alreadyDispatchedToNewTouchTarget,在Down事件里有过这样代码:
        alreadyDispatchedToNewTouchTarget = true;   所以一旦执行Down后else{..}就直接return:
而在后续的非Down事件中,由于alreadyDispatchedToNewTouchTarget默认为false,则会执行
        else {
            final boolean cancelChild = resetCancelNextUpFlag(target.child)
                    || intercepted;
            if (dispatchTransformedTouchEvent(ev, cancelChild,
                    target.child, target.pointerIdBits)) {
                handled = true;
            }
内部是不是又将事件交给child执行了,自己返回true。 这样一个完整的事件分发机制就ok了。
 
 
 
 
 
 
最后来个大总结:      
	  区分拦截与不拦截:
              拦截会导致自己的mFristTouchTarget==null,进而调用自己的OnTouch或者onTouchEvent
	       不拦截则会将事件交给child根据child的返回值判断事件是否消耗。
              而拦截与不拦截最终还是要决定是否消耗事件的。无非就是拦截调用自己的方法,不拦截调用child的方法。
     
	  关于事件的消耗: 
		onTouch()或者onTouchEvent()的返回值都会决定事件是否消耗。      		 			
		对于一个Down事件,它的所有View都能收到(默认不拦截情况下)(仅仅只是收到),
		但是是否执行onTouch或者onTouchEvent()的掌控权就先交给了最末端的View(非ViewGroup,它的Parent全是ViewGroup)	
如果这个View表示不消耗(肯定会执行一次onTouch或者onTouchEvent),那就会再次执行这个View最近的Parent的onTouch或者onTouchEvent,然后决定权就交给了它,
                然后就一直向上传递。  如果有一个ViewGroup表示可以消耗,那么Down事件的后续事件都会交给它,其他的View都不会参与(这个ViewGroup后的不能接收)。
		其实机制就是当一个View或者ViewGroup表示消耗时往后的View或者ViewGroup里的mFristTouchTarget=null(包括自己)往前(向DecorView) 的mFristTouchTarget!=null
		进而导致调用了super(自己)或者child的处理事件方法。
		如果最末端的View表示可以消耗,那么所有的ViewGroup的mFristTouchTarget!=null,  后续的事件就全交给这个View执行。
		如果ViewGroup和View都表示消耗,则最末端的优先级最高!
							
    Down拦截: 如果一个ViewGroup对Down事件拦截,那么事件将不能继续往下传递,而后续的MOVE,UP事件能否处理取决于这个ViewGroup的Down事件返回值,为true 则都交给这个ViewGroup,MOVE与UP事件的返回值不影响

   MOVE拦截: 如果一个ViewGroup的Child在Down事件中返回true,则默认后续事件都交给它,但此时如果在这个ViewGroup的MOVE中拦截,那么后续的MOVE,UP事件都会交给ViewGroup
 
 
 
 
   UP拦截:  这个拦截没有意义,当Down事件默认被Child处理这时ViewGroup表示UP拦截,那么那个都不能接收UP事件,如果在这个UP事件之前得事件都被这个ViewGroup拦截那么无论UP是否拦截,则都交给ViewGroup所以说UP拦截没有意义		   
   对于上述拦截的前提是有事件能传递过来,而事件能传递过来的前提就是child的Down事件返回为true,这样才能保证它的Parent有机会拦截后续事件。        
		
   

猜你喜欢

转载自blog.csdn.net/qq_36043263/article/details/78848512
今日推荐