如果遍历所有的子元素后事件都没有被处理的时候,那么 ViewGroup 就会自己处理点击事件,这里包含 2 种情况下 ViewGroup 会自己处理事件 (其一: ViewGroup 没有子元素,其二:子元素处理了点击事件,但是在 dispatchTouchEvent 中返回了false,这一般是在子元素的 onTouchEvent 中返回了 false )
代码如下:
public boolean dispatchTouchEvent(MotionEvent ev) {
…
if (mFirstTouchTarget == null) {
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
}
…
}
复制代码
可以看到如果 mFirstTouchTarget == null 的时候,那么就是代表 ViewGroup 的子 View 没有被消费点击事件,将调用自身的 dispatchTransformedTouchEvent 方法。注意上面这段代码这里的第三个参数 child 为 null ,从前面的分析可以知道,它会调用 super.dispatchTouchEvent(event) ,显然,这里就会调用父类 View 的 dispatchTouchEvent 方法,即点击事件开始交由 View 处理,请看下面的分析:
- View 对点击事件的处理过程
其实 View 对点击事件的处理过程稍微简单一些,注意这里的 View 不包含 ViewGroup 。先看它的 dispatchTouchEvent 方法,代码如下:
//View.java
public boolean dispatchTouchEvent(MotionEvent event) {
…
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
ListenerInfo li = mListenerInfo;
//1.
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
//2.
if (!result && onTouchEvent(event)) {
result = true;
}
}
…
return result;
}
View 中的事件处理逻辑比较简单,我们先看注释 1 处,如果我们外部设置了 mOnTouchListener 点击事件,那么就会执行 onTouch 回调,如果该回调的返回值为 false ,那么才会执行 onTouchEvent 方法,可见onTouchListener 优先级高于 onTouchEvent 方法,下面我们来分析 onTouchEvent 方法实现,代码如下:
//View.java
public boolean onTouchEvent(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
final int viewFlags = mViewFlags;
final int action = event.getAction();
final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
|| (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
/**
- 1. View 处于不可用状态下的点击事件的处理过程
*/
if ((viewFlags & ENABLED_MASK) == DISABLED) {
if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
setPressed(false);
}
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
// A disabled view that is clickable still consumes the touch
// events, it just doesn’t respond to them.
return clickable;
}
/**
- 2. 如果 View 设置了代理,那么还会执行 TouchDelegate 的 onTouchEvent 方法。
*/
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
/**
- 3. 如果 clickable 或 (viewFlags & TOOLTIP) == TOOLTIP 有一个成立那么就会处理该事件
*/
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
case MotionEvent.ACTION_UP:
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
if ((viewFlags & TOOLTIP) == TOOLTIP) {
handleTooltipUp();
}
if (!clickable) {
removeTapCallback();
removeLongPressCallback();
mInContextButtonPress = false;
mHasPerformedLongPress = false;
mIgnoreNextUpEvent = false;
break;
}
// 用于识别快速按下
boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
if (prepressed) {
setPressed(true, x, y);
}
if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
removeLongPressCallback();
if (!focusTaken) {
if (mPerformClick == null) {
mPerformClick = new Perfo