事件:MotionEvent
ACTION_DOWN 手指初次接触到屏幕时触发
ACTION_MOVE 手指在屏幕上移动得时触发,会多次触发
ACTION_UP 手指离开屏幕时触发
ACTION_CANCEL 事件被上层拦截时触发
事件传递层级:
Activity -> Window -> DecorView -> ViewGroup -> View
View
//因为view不是容器,里面不会再有子view,所以该方法不具备分发事件,而是去处理事件
dispatchTouchEvent(MotionEvent event){
boolean result = false; //返回值默认为false
if(onFilterTouchEventForSecurity(event)){ //事件是否合法,一般情况下是合法的
ListenerInfo li = mListenerInfo; //如果调用了view的setOnClickListener的方法,那么该li就不会为空
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED //view是不是enable
//如果onTouch返回为true,说明该事件被处理,事件结束
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
//如果onTouch返回为false,执行onTouchEvent(event)
//java中的 && 是短路与,所以如果onTouch返回true后就不会调用onTouchEvent(event)
if (!result && onTouchEvent(event)) {
result = true;
}
}
} -> onTouchEvent(event){
// 分别处理各个事件
switch (action) {
case MotionEvent.ACTION_UP:
performClickInternal -> performClick ->{
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this); //调用onClick方法
result = true;
}else{
result false;
}
}
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_MOVE:
}
}
通过上述代码,可以得出一个结论:
如果一个view同时实现了onClick和onTouch方法,如果onTouch返回ture(true表示事件被消费),则onClick方法不会被调用,反之onTouch返回false才会执行onClick
ViewGroup:
dispatchTouchEvent(MotionEvent ev){
// 1、去判断是否需要拦截事件
// 2、在当前viewGroup的子view中找到用户真正点击的view
// 3、分发事件到view
boolean handled = false;//返回值默认为false
//DOWN事件时,重置target
if (actionMasked == MotionEvent.ACTION_DOWN) {
cancelAndClearTouchTargets(ev); ->{ mFirstTouchTarget = null; }
resetTouchState(); -> { mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; }
}
// 判断当前事件是否需要被拦截,true表示viewgroup会拦截事件,不在继续向子view分发
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
// view可以通过接口 (requestDisallowInterceptTouchEvent(boolean disallowIntercept))
// 设置disallowIntercept的值,告诉viewGroup不截断事件
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;
}
//事件非canceled、不拦截,说明该事件需要向下分发
if (!canceled && !intercepted) {
for (int i = childrenCount - 1; i >= 0; i--) {
//若if命中,说明有子view/viewgroup消费该事件
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
->addTouchTarget(){
final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
target.next = mFirstTouchTarget;
mFirstTouchTarget = target;
}
alreadyDispatchedToNewTouchTarget = true
} -> child.dispatchTouchEvent(event);
} // 如果所有子view/viewgroup都没有响应事件,则该事件处理流程同拦截一致
}
//事件被viewgroup拦截
if (mFirstTouchTarget == null) {
// 调用view的dispatchTouchEvent处理事件
handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);
-> super.dispatchTouchEvent(event);
} else {
TouchTarget target = mFirstTouchTarget;
while (target != null) { //单点事件只会循环一次,多点触控才会多次循环
final TouchTarget next = target.next;
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)){
handled = true;
}
}
}
target = next;
}
return handled;
}
同一事件序列,如果子view(包括viewgroup)没有处理该事件(即没有消费该事件),那么后续事件就不会传递到子view中