这是学习《android开发艺术探究》的笔记 如果有什么不对的地方,欢迎指出。
1.验证P143第四点
(4) 某个View一旦开始处理事件(即:onTouchEvent接受到事件),如果它不消耗掉ACTION_DOWN事件(onTouchEvent返回false),那么同一事件序列中的其他事件都不会被交给它处理,并且事件将重新提交,由父元素的onTouchEvent处理(父元素将处理ACIONT_DOWN,ACTION_MOVE,ACTION_UP)。
情景 1. onInterceptTouchEvent始终拦截事件,onTouchEvent不消耗ACTION_DOWN事件
public class MyViewGroup extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
String ActionStr = Util.getActionStr(action);
boolean consume;
consume = true;
Log.i(TAG, "onInterceptTouchEvent"+(consume?"拦截":"不拦截") + ActionStr);
return consume;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
String ActionStr = Util.getActionStr(action);
boolean consume;
if (action == MotionEvent.ACTION_DOWN) {
consume = false;
} else {
consume = true;
}
Log.i(TAG, "dispatchTouchEvent"+(consume?"消耗":"不消耗") + ActionStr);
return consume;
}
}
结果:接受不到后续事件
onInterceptTouchEvent拦截ACTION_DOWN
onTouchEvent不消耗ACTION_DOWN
情景2.特例 onInterceptTouchEvent不拦截ACTION_DOWN事件,拦截其他事件,onTouchEvent不消耗事件(因为onTouchEvent没有对ACTOIN_DOWN事件返回false,所以onInterceptTouchEvent仍能接受到其他事件)
public class MyViewGroup extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
String ActionStr = Util.getActionStr(action);
boolean consume;
if (action == MotionEvent.ACTION_DOWN) {
consume = false;
} else {
consume = true;
}
Log.i(TAG, "onInterceptTouchEvent"+(consume?"拦截":"不拦截") + ActionStr);
return consume;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
String ActionStr = Util.getActionStr(action);
boolean consume;
consume = false;
Log.i(TAG, "dispatchTouchEvent"+(consume?"消耗":"不消耗") + ActionStr);
return consume;
}
.....
}
结果:因为onTouchEvent没有对ACTOIN_DOWN事件返回false,所以onTouchEvent仍能接受到其他事件(同时说明了第三点,如果事件被拦截,则同一事件序列都由onTouchEvent处理)
onInterceptTouchEvent不拦截ACTION_DOWN
onInterceptTouchEvent拦截ACTION_MOVE
onTouchEvent不消耗ACTION_MOVE
onTouchEvent不消耗ACTION_MOVE
onTouchEvent不消耗ACTION_MOVE
onTouchEvent不消耗ACTION_MOVE
onTouchEvent不消耗ACTION_MOVE
onTouchEvent不消耗ACTION_UP
2.源码分析
if (!canceled && !intercepted) {
for(遍历child){
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
newTouchTarget = addTouchTarget(child, idBitsToAssign);
break;
}
}
}
if (mFirstTouchTarget == null) {
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
}
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
}
/**
* Adds a touch target for specified child to the beginning of the list.
* Assumes the target child is not already present.
*/
private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
target.next = mFirstTouchTarget;
mFirstTouchTarget = target;
return target;
}
2.1 关于源码的几点解说
-
dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits)
- chile==null,ViewGroup的onTouchEvent处理
- chile!=null,Child的onTouchEvent处理
- dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)返回true表示child消耗掉了事件,否则没有消耗。
- addTouchTarget会对mFirstTouchTarget进行赋值,使mFirstTouchTarget!=null。
- mFirstTouchTarget==null,有两种情况,一种是事件被拦截了,另一种是事件被拦截但是没有child消耗事件。
2.2 源码逻辑
如果child不消耗掉ACTION_DOWN事件,即dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)返回false,
则mFirstTouchTarget==null,
那么会导致
- dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS)会被调用,ViewGroup去处理ACTION_DOWN事件
- 在处理后续事件(MOVE,UP)时,actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null不成立,ViewGrop直接拦截事件,dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS)被调用。
所以文中才会说
某个View一旦开始处理事件(即:onTouchEvent接受到事件),如果它不消耗掉ACTION_DOWN事件(onTouchEvent返回false),那么同一事件序列中的其他事件都不会被交给它处理,并且事件将重新提交,由父元素的onTouchEvent处理(父元素将处理ACIONT_DOWN,ACTION_MOVE,ACTION_UP)。
网友评论