最近在开发过程中遇到了有关处理和拦截点击事件的逻辑问题,在这里稍微进行一下总结~
①Android处理TouchEvent的流程
首先来看一下跟Touch事件相关的三个方法:
public boolean dispatchTouchEvent(MotionEvent ev); //用来分派event
public boolean onInterceptTouchEvent(MotionEvent ev); //用来拦截event,ViewGroup可用,View不可用
public boolean onTouchEvent(MotionEvent ev); //用来处理event
举例说明:
假设我们现在拥有一个Textview,一个LinerLayout,TextView位于LinerLayout中,布局大体文件如下:
<LinerLayout>
<TextView>
</TextView>
</LinerLayout>
当我们点击屏幕时,触发一个TouchEvent,这个事件的处理流程是:
(1)首先由顶层的View也就是Activity获取到,由Acticity的dispatchTouchEvent进行分派,默认将其传递至Activity的onInterceptTouchEvent,返回值为super.dispatchTouchEvent;
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
(2)Activity的onInterceptTouchEvent获取到分派函数分派的TouchEvent,决定是否将其拦截在这里。
public boolean onInterceptTouchEvent (MotionEvent event) {
return super.onInterceptTouchEvent(ev);
}
如果进行拦截(返回值为True),就不继续分发,同时将调用Acticity的onTouchEvent;如果不进行拦截(返回值为False,为默认操作),则将该Event下发至下一个View的dispatchTouchEvent;
(3)如果Event在上一步没有被拦截,此时调用LinerLayout的dispatchEvent和onInterceptTouchEvent;
(4)如果Event在上一步没有被拦截,此时调用TextView的dispatchEvent,由于TextView不是ViewGroup,则直接调用TextView的onTouchEvent;
(5)TextView的onTouchEvent决定是否消费(consume)这个Event,如果返回值为True,则该Event终止,流程结束;否则将其传回上一级的onTouchEvent(此为默认操作);
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
(6)如果TextView的onTouchEvent没有消费这个Event,那么由LinerLayout的onTouchEvent处理该事件;
(7)如果LinerLayout的onTouchEvent没有消费这个Event,那么由Acticity的onTouchEvent处理该事件,流程结束。
需要注意的是:
(1)如果TextView的Clickable属性为True,那么TextView就会消费掉TouchEvent,不再进行回传。
(2)每一个dispatchTouchEvent会记录事件是否被成功处理。如果dispatchTouchEvent检测到该层的onTouchEvent被调用了,那么当下一个事件传递来时,dispatchTouchEvent会自动将事件分派给本层的onTouchEvent而不向下分发,这一点会导致很多BUG,请大家务必注意!