TouchEvent: dispatchTouchEvent(), onTouch() , onTouchEvent(), requestDisallowInterceptTouchEvent() 方法中的一些细节
Q: onTouchListener与onClickListener谁先执行?
A: onTouchListener中的内容先执行。若其中的onTouch方法返回true,代表该事件已被onTouch消费掉了,则onClick不会再执行。
Q: onTouch和onTouchEvent有什么区别?
A: 在某种情况下onTouch要先于onTouchEvent执行。onTouch是 onTouchListener 里的方法,若View已经设置了onTouchListener,且该View是 Enable 的,则会先尝试先调用onTouchListener中的onTouch方法,判断返回值。若onTouch方法返回false,则继续向下执行 onTouchEvent() 方法;若onTouch()方法返回true,则不再执行 onTouchEvent() 方法。
参考源码:
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event); }
Q: onClick()方法是在哪里调用的?是如何调用的?
A: onClick()方法是在onTouchEvent()方法中调用的。大概的调用流程为:当收到 MotionEvent.ACTION_UP 事件后,经过层层判断,会跳转到到 performClick() 方法中,在该方法中会判断onClickListener
是否为null, 若不为null,则会调用 onClickListener 的 onClick 方法。
参考源码: onTouchEvent
performClick()
public boolean performClick() { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); if (mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnClickListener.onClick(this); return true; } return false; }
Q: 有些时候在自定义View中的onTouchEvent()方法里添加GestureDetector时,无法响应GestureDetector里的触摸事件,这是为什么?
A: 可能是由于该View无法 clickable 导致的。观察源码的 onTouchEvent 方法就可以发现,如果View要响应 ACTION_UP , ACTION_MOVE ...等等诸如此类事件,先决条件就是该View必须是 CLICKABLE 或
LONG_CLICKABLE 的,二者满足其一即可。若二者皆不满足,则不会进入到接下来的 switch (event.getAction()) 代码块中。
参考源码:
Q: android里的Touch事件传递流程具体是怎么样的?
A: 当在屏幕上点击了一个控件,首先会去调用该控件所在的顶级布局中的 dispatchTouchEvent() 方法,然后在该方法中判断 if (disallowIntercept || !onInterceptTouchEvent(ev))
disallowIntercept 代表的是否禁用掉当前View的事件拦截功能,默认是 false ; onInterceptTouchEvent 代表的则是是否拦截其中的某一个事件,默认也是 false ,但是对onInterceptTouchEvent
进行了取反,也就意味着能够进入接下来的方法块当中,紧接着在该方法块中寻找符合点击位置的子控件,若找到了该子控件然后再去调用该子控件的dispatchTouchEvent()方法,最后调用该子控件的 onTouch 或
onTouchEvent() 方法对事件进行处理。
参考源码:
这几个方法的主要作用在于:
dispatchTouchEvent 负责事件的分发,
onInterceptTouchEvent 和 disallowIntercept 用于控制具体的触摸事件是否需要向对下层过滤
onTouch和onTouchEvent 负责具体的事件处理
正常的事件流向(以MyTextView为例):
Q: requestDisallowInterceptTouchEvent方法是干什么用的?
A: 这个方法的主要作用是用于修改上面的 disallowIntercept 这个变量的值,该方法传入一个bool变量,若为true,则代表禁用掉当前View的事件拦截功能。
参考链接:
1.Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
2.Android事件分发机制完全解析,带你从源码的角度彻底理解(下)