对于大多数Android开发来说事件分发机制较为繁琐,今天我们就来了解一下Android的事件分发机制。 Android中事件分发机制主要涉及DispatchTouchEvent、onInterceptTouchEvent、onTouchEvent这三个方法。当然setOnTouchListener和setOnClickListener对事件分发也会有影响。
接下来我们先来了解一下事件的传递,在Android中事件的传递顺序是Activity->Window->View。 既然如此我们就先来了解一下Activity中的事件分发处理。
<span style="white-space:pre"> </span>`public boolean dispatchTouchEvent(MotionEvent event){
<span style="white-space:pre"> </span>if(event.getAction()==MotionEvent.ACTION_DOWN){
<span style="white-space:pre"> </span>onUserInteraction();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if(getWindow().superDispatchTouchEvent(event)){
<span style="white-space:pre"> </span> return true;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return onTouchEvent(event);
<span style="white-space:pre"> </span>}`
在这里我们可以看到Activity将事件传递给了Window的superDispatchTouchEvent方法。而在superDispatchTouchEvent方法中又将事件传递给了DecorView。
```public boolean superDispatchTouchEvent(MotionEvent ev){
<span style="white-space:pre"> </span>return mDecor.superDistouchEvent(ev);
<span style="white-space:pre"> </span>}```
那么这个DecorView是什么东西呢?其实这个DecorView就是顶层view。也就是在Activity中的onCreate方法中使用setContentView填充的View。一般这个顶层view都是一个viewGroup,接下来就是view中的事件分发。
在讲这个view的事件分发之前我们先回忆一些常见的面试知识点。
dispatchTouchEvent默认的返回值是true。此方法返回true则代表后续事件会进行分发,返回false则代表后续事件不会分发。
onInterceptTouchEvent默认的返回值是false。此方法如果返回true则代表对此次事件进行拦截,如果返回false,则代表不拦截本次事件。
onTouchEvent默认的返回值是true,此方法返回true则代表本次事件会被消费,如果返回false则代表本次事件不会被销费。
只有在ViewGroup中才会调用onInterceptTouchEvent,上面三个方法调用的顺序是dispatchEvent->onInterceptTouchEvent->onTouchEvent。
了解了以上这些基本知识之后我们通过图片来分析view的事件分发机制。
常见的事件有ACTION_DOWN,ACTION_MOVE,ACTION_UP,每个事件都需要经过上面所述的三个方法。
除此之外,我们来看一下setOnTouchListener和setOnClickListener对事件分发的影响。如果设置了setOnTouchListener在onTouch方法中返回true的话则不会执行他的onTouchEvent方法,如果返回false,则onTouchEvent会被执行。另外设置了view的点击事件之后,这个点击事件在onTouchEvent中会被执行。
如果一个view的clickable或者longClickable都为false的时候onTouchEvent返回的是false。
一般情况下view是不能影响别的view的事件处理,但是如果在子view中调用requestDisallowInterceptTouchEvent可以干扰父View的事件处理,注意的是父View的ACTION_DOWN不能被干扰。