Android事件拦截机制
事件拦截
主要是View的onInterceptTouchEvent()方法对touch事件进行拦截。
onInterceptTouchEvent:Touch事件拦截方法
图示:
从外到里的View包含关系依次为:A->B->C->D
(1)onInterceptTouchEvent()方法对touch事件进行拦截,对于嵌套的View,最先执行的是最外层View的onInterceptTouchEvent()方法。然后依次执行子视图的onInterceptTouchEvent()方法,子视图的子视图的onInterceptTouchEvent()方法。(这里假设所有嵌套视图的onInterceptTouchEvent都会得到执行,即每一个View的onInterceptTouchEvent方法返回都为false的情况)
参照上图,事件拦截顺序:onInterceptTouchEvent执行顺序依次为:A->B->C->D,也就是父视图向子视图传递。
总之,事件拦截机制是由父视图开始发起对事件的拦截(出事了老子先上,儿子稍后)。参照上图当手指触摸事件时,父视图A首先发起对该起事件的拦截,如果A拦截失败,就交给它的子视图B进行拦截;如果B拦截失败就交给B的子视图C再进行拦截..直到某一子视图对该次事件拦截成功。
(2)某一视图拦截事件成功与否的判断标识是onInterceptTouchEvent方法的返回值,当返回true的时候说明拦截成功,返回false的时候说明当前视图对事件拦截失败。
也就是说,只有当父视图的onInterceptTouchEvent返回为false时,事件才向子视图onInterceptTouchEvent传递。返回为true时,表示事件拦截成功,不再向下传递,事件交由该View的onTouchEvent方法来处理。子视图的onInterceptTouchEvent不会执行。
(3)拦截成功情况
视图C对当前的touch事件拦截成功:此时意味着C的onInterceptTouchEvent方法返回true,事件将不再向D进行传递。事件拦截成功后,紧接着需要对拦截的事件进行处理,由视图C的onTouchEvent方法来执行。这是不是就意味着当前touch事件是由C视图的onTouchEvent方法来处理的呢?
这要由C视图的onTouchEvent方法的返回值来决定。当C视图的onTouchEvent返回true的时候,当前事件就由C全权处理。
处理的当然是事件的各种action,什么MotionEvent.ACTION_MOVE,ACTION_UP都交给了C的onTouchEvent方法进行处理。所以此时就可以在C的onTouchEvent方法中进行switch(event.getAction)判断执行相关逻辑了。
如果返回的false,说明C视图对此事件不做处理或者处理不了,怎么办呢?儿子不行老爸来,于是事件就交到了B视图的onTouchEvent方法中。同样B对此事件处理与否还是看B的onTouchEvent返回值,具体的解释就跟C一样了,不复多言。
(4)拦截失败情况
如上图,在A B C D的onInterceptTouchEvent和onTouchEvent都返回false的情况下,方法执行的顺序依次为A.onInterceptTouchEvent-->B.onInterceptTouchEvent-->C.onInterceptTouchEvent-->D.touchEvent(最深的子视图没重写onInterceptTouchEvent)-->C.touchEvent-->B.touchEvent-->A.touchEvent.
也就是说拦截事件是父视图优先有子视图进行拦截,处理事件是子视图优先父视图进行处理。
总结:onInterceptTouchEvent负责对事件进行拦截,拦截成功后交给最先遇到onTouchEvent返回true的那个view进行处理。
图解:
一、onInterceptTouchEvent方法返回值情况(此时默认每个onTouchEvent都返回false)
(1)所有ABCD视图都对该事件不拦截和不处理的情况,当传递到最末端的子视图D时对touch事件进行处理,之后事件处理向父视图传递。(默认叶子View是没有onInterceptTouchEvent方法的,只有onTouchEvent事件进行事件处理),也就是所有的onIntercetpTouchEvent方法和onTouchEvent方法都返回false值。
(2)A视图的onInterceptTouchEvent方法对事件进行了拦截,即返回true,则:事件不再向子视图传递,此时由A的onTouchEvent方法进行事件处理。
(3)只有B的onInterceptTouchEvent方法对事件进行了拦截,即返回true,则:事件不再向子视图传递,此时由B的onTouchEvent方法进行事件处理。若此时B视图的onTouchEvent方法返回false,则事件向B的父视图A传递。
(4)同理,只有C的onInterceptTouchEvent方法对事件进行了拦截,即返回true,则:事件不再向子视图传递,此时由C的onTouchEvent方法进行事件处理。若此时C视图的onTouchEvent方法返回false,则事件向C的父视图B传递。
二、onTouchEvent方法返回值情况(此时默认每个onInterceptTouchEvent都返回false,对事件不拦截)
(1)当D的onTouchEvent方法返回true,则表明D对该touch事件全权处理,事件不再向父视图传递。
img(2)当C的onTouchEvent方法返回true,则表明D处理不了该事件,交由C对该touch事件全权处理,事件不再向父视图B传递。
img三、dispatchTouchEvent的返回值情况(该方法只有Activity和ViewGroup含有,View不含)
dispatchTouchEvent顾名思义,事件分发
一般事件分发,都是从Activity的DispatchTouchEvent收到触摸事件的Action_down的时候,再将事件分发给ViewGroup的DispatchTouchEvent的。(事件都是从ACTION_DOWN开始的,Activity的dispatchTouchEvent()首先接收到ACTION_DOWN,执行super.dispatchTouchEvent(ev),事件向下分发。)
dispatchTouchEvent()返回true,后续事件(ACTION_MOVE、ACTION_UP)会再传递,如果返回false,dispatchTouchEvent()就接收不到ACTION_UP、ACTION_MOVE。
(1)ACTION_DOWN都没被消费
(2)a、ACTION_DOWN被View消费了
b、后续ACTION_MOVE和UP在不被拦截的情况下都会去找VIEW
(3)后续的被拦截了
Touch事件
android中的Touch事件都是从ACTION_DOWN开始的:
单手指操作:ACTION_DOWN -> ACTION_MOVE -> ACTION_UP
多手指操作:ACTION_DOWN -> ACTION_POINTER_DOWN -> ACTION_MOVE -> ACTION_POINTER_UP -> ACTION_UP.
参考文章:
https://blog.csdn.net/chunqiuwei/article/details/41084921
https://www.jianshu.com/p/9f521f34386a
https://blog.csdn.net/xyz_lmn/article/details/12517911