一、View有dispatchTouchEvent方法和onTouchEvent方法
在View的dispatchTouchEvent中,如果View设置了onTouchListener,会先执行该Listener的onTouch方法,如果返回true,则dispatchTouchEvent方法直接返回true,这个事件到此结束;如果返回false,则执行onTouchEvent方法。如果View没设置onTouchListener,则直接进入onTouchEvent方法。
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
onTouchEvent方法主要是处理click和longClick事件的,如果View是可点击的,那么一定返回true,否则返回false。也就是说一个事件结束的标志是dispatchTouchEvent返回true,想让dispatchTouchEvent返回false,只有View是不可点击的这一种情况。当然也可以自己重写onTouchEvent方法,去处理滑动事件,自己决定返回true或false来实现一些逻辑。
public boolean onTouchEvent(MotionEvent event) {
final int viewFlags = mViewFlags;
if ((viewFlags & ENABLED_MASK) == DISABLED) {
// A disabled view that is clickable still consumes the touch
// events, it just doesn't respond to them.
return (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
}
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
// take focus if we don't have it already and we should in
// touch mode.
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
if (!mHasPerformedLongPress) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick(); //在这里执行设置的ClickListener的onClick方法
}
}
}
if (mUnsetPressedState == null) {
mUnsetPressedState = new UnsetPressedState();
}
if (prepressed) {
mPrivateFlags |= PRESSED;
refreshDrawableState();
postDelayed(mUnsetPressedState,
ViewConfiguration.getPressedStateDuration());
} else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
removeTapCallback();
}
break;
case MotionEvent.ACTION_DOWN:
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
mPrivateFlags |= PREPRESSED;
mHasPerformedLongPress = false;
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
break;
case MotionEvent.ACTION_CANCEL:
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
removeTapCallback();
break;
case MotionEvent.ACTION_MOVE:
final int x = (int) event.getX();
final int y = (int) event.getY();
// Be lenient about moving outside of buttons
int slop = mTouchSlop;
if ((x < 0 - slop) || (x >= getWidth() + slop) ||
(y < 0 - slop) || (y >= getHeight() + slop)) {
// Outside button
removeTapCallback();
if ((mPrivateFlags & PRESSED) != 0) {
// Remove any future long press/tap checks
removeLongPressCallback();
// Need to switch from pressed to not pressed
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
}
}
break;
}
return true; //只要是可点击的都会返回true
}
return false; //否则就会返回false
}
二、ViewGroup有dispatchTouchEvent方法、onInterceptTouchEvent方法和onTouchEvent方法
如果onInterceptTouchEvent方法返回false,即不拦截事件,那么事件就会根据触摸位置分发给子View,执行子View的dispatchTouchEvent方法。如果拦截,那么target为null,就执行ViewGroup的父类的dispatchTouchEvent方法(super.dispatchTouchEvent,执行的是View中的dispatchTouchEvent,即先onTouch,再onTouchEvent,再onClick)。还有两种情况,当不拦截时,如果触摸位置下没有子View,那么自然下发不下去,target为null,如果有子View但不可点击(即执行子View的dispatchTouchEvent方法返回false)则target也为null,这两种情况都会执行ViewGroup的父View的dispatchTouchEvent方法(onTouch,再onTouchEvent,再onClick)。
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final float xf = ev.getX();
final float yf = ev.getY();
final float scrolledXFloat = xf + mScrollX;
final float scrolledYFloat = yf + mScrollY;
final Rect frame = mTempRect;
boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (action == MotionEvent.ACTION_DOWN) {
if (mMotionTarget != null) {
mMotionTarget = null;
}
//如果不拦截就进入
if (disallowIntercept || !onInterceptTouchEvent(ev)) {
ev.setAction(MotionEvent.ACTION_DOWN);
final int scrolledXInt = (int) scrolledXFloat;
final int scrolledYInt = (int) scrolledYFloat;
final View[] children = mChildren;
final int count = mChildrenCount;
for (int i = count - 1; i >= 0; i--) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
|| child.getAnimation() != null) {
child.getHitRect(frame);
//如果触摸位置下有子View就进入
if (frame.contains(scrolledXInt, scrolledYInt)) {
final float xc = scrolledXFloat - child.mLeft;
final float yc = scrolledYFloat - child.mTop;
ev.setLocation(xc, yc);
child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
//将事件分发给子View
if (child.dispatchTouchEvent(ev)) {
//只有子View的dispatchTouchEvent返回true,mMotionTarget才会被赋值,
//ViewGroup的dispatchTouchEvent也会返回true,这个Down事件结束
mMotionTarget = child;
return true;
}
}
}
}
}
}
boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
(action == MotionEvent.ACTION_CANCEL);
if (isUpOrCancel) {
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
//当ViewGroup拦截事件时,或者触摸位置下没有子View时,或者子View的dispatchTouchEvent方法返回false时
//(可能是因为子View不可点击,或者人为重写onTouchEvent返回false),都会使得target为null
final View target = mMotionTarget;
if (target == null) {
ev.setLocation(xf, yf);
if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
ev.setAction(MotionEvent.ACTION_CANCEL);
mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
}
//如果target为null,就执行ViewGroup的父类的dispatchTouchEvent(ViewGroup是View的子类,重写了View的
//的dispatchTouchEvent方法,这里相当于调用父类View的方法,即依次调用onTouch---onTouchEvent---onClick)
//如果ViewGroup的dispatchTouchEvent还是返回false的话,那么就继续往上找父容器,直到一个ViewGroup的
//dispatchTouchEvent方法返回了true,这个Down事件到此结束。由于在Down事件时使得target为null,错过了唯一
//赋值的机会,接下来同一事件序列中的事件都会因为target为null直接执行ViewGroup的父类的dispatchTouchEvent
//(这个ViewGroup就是返回了true的那个ViewGroup)。也就是说这个ViewGroup将这个事件序列接下来的事件都包揽了
return super.dispatchTouchEvent(ev);
}
if (!disallowIntercept && onInterceptTouchEvent(ev)) {
final float xc = scrolledXFloat - (float) target.mLeft;
final float yc = scrolledYFloat - (float) target.mTop;
mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
ev.setAction(MotionEvent.ACTION_CANCEL);
ev.setLocation(xc, yc);
if (!target.dispatchTouchEvent(ev)) {
}
mMotionTarget = null;
return true;
}
if (isUpOrCancel) {
mMotionTarget = null;
}
final float xc = scrolledXFloat - (float) target.mLeft;
final float yc = scrolledYFloat - (float) target.mTop;
ev.setLocation(xc, yc);
if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
ev.setAction(MotionEvent.ACTION_CANCEL);
target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
mMotionTarget = null;
}
//如果target不为null,即子View处理了Down事件返回true,那么该事件序列接下来的事件分发给子View
return target.dispatchTouchEvent(ev);
}