Android事件分发机制完全解析(终极版二)

大家好,我是你们的康志哥。

Android 事件传递机制是个很复杂的过程,大家读完Android事件分发机制完全解析(终极版)后,假如还有疑问,欢迎继续阅读这篇更加详细的分析文章,此篇文章还会介绍Android事件分发机制中对事件序列的处理。

-----------------------------------------------------------------------------------------------------------------------------------------------------------

首先要知道我们对于屏幕的所有操作,包括点击、放开、滑动,以及由这些基本操作组成的放大、缩小、旋转等操作全部是被封装在MotionEvent对象中进行操作的。我们需要通过getAction()判断是何种事件。这些事件包括如下6种:

ACTION_DOWN: 第一个点按下时触发

ACTION_UP: 屏幕上唯一的一个点抬起时触发

ACTION_MOVE: 当屏幕上的点移动时触发。

ACTION_POINTER_DOWN: 当屏幕上已经有一点按住,再按下其他点便会触发该事件。

ACTION_POINTER_UP: 当屏幕上有多个点被按住,松开其中的点时触发(非最后一个点,最后一个点触发ACTION_UP)。

ACTION_CANCEL:当前的手势被释放时会触发,当前手势指的是从ACTION_DOWN开始以及后面一系列的ACTION_MOVE、ACTION_POINTER_DOWN、ACTION_POINTER_UP操作。

其中, 事件序列的概念:

同一个事件序列是指从手指接触屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中所产生的一系列事件,这个事件序列以down事件开始,中间含有数量不定的move事件,最终以up事件结束。

事件序列并不是一个list,它们是独立的MotionEvent,一个一个地出现和被处理。

到这里我们就可以写出屏幕触摸事件相应的代码了:

[java]  view plain  copy
  1. @Override  
  2.     public boolean onTouchEvent(MotionEvent ev) {  
  3.   
  4.         switch (ev.getAction()) {  
  5.         case MotionEvent.ACTION_DOWN:  
  6.             // 第一个点按下去的相关处理  
  7.             break;  
  8.         case MotionEvent.ACTION_MOVE:  
  9.             // 手指在屏幕上移动相关处理  
  10.             break;  
  11.         case MotionEvent.ACTION_UP:  
  12.             // 屏幕上最后一个点离开屏幕时相关处理  
  13.             break;  
  14.         }  
  15.         return super.onTouchEvent(ev);  
  16.     }  

只要把握这六种事件就可以了,是不是很简单呢?但是Touch事件并非这么简单,到这里还有很多问题没有搞清楚。Touch事件的事件源,处理者是谁?处理的具体方法有哪些?具体的流程如何?下面还请听详细分解。

Touch事件传递

Touch事件的处理分为三个层面:Activity,ViewGroup,View。我们所说的Touch事件传递便是在这三个层面之间进行传递的。而事件的传递,依靠的是三个方法dispatchTouchEvent()­­­----事件分派,onInterceptTouchEvent()----事件拦截,onTouchEvent()----事件处理。我们上面看到的示例代码中onTouchEvent()便是我们实际处理操作的方法。而至于事件是如何传递的,上面我们并不清楚。下表给出这三个层次具体的实例类和和这三个方法之间的关系。

层次

实例类

方法

Activity

 

dispatchTouchEvent, onTouchEvent

ViewGroup

RelativeLayout, FrameLayout, LinearLayout, 

AbsoluteLayout, ListView,ScrollView...

dispatchTouchEvent, onInterceptTouchEvent, 

onTouchEvent

View

Button, EditText, TextView, ImageView

dispatchTouchEvent, onTouchEvent 

表一 三个层次及其具体实例类和三个方法之间的对应关系

下面将通过一个示例来表现Touch事件究竟是如何在这三个层面之间进行传递的。我们拿下面这张图来作为Touch事件传递的层次图。

Android事件分发机制完全解析(终极版二)_第1张图片

图一 Touch事件传递涉及层次图

所有的Touch事件一定都是从ACTION_DOWN这个事件开始的,那么当你按下屏幕那一刻开始,也就是触发了ACTION_DOWN这个事件。Touch事件传递便开始工作了。以上面这张图为例。

当ACTION_DOWN被触发,系统会调用Activity的dispatchTouchEvent方法,对该事件进行分发,然后将事件分发到RelativeLayout的dispatchTouchEvent方法进行处理。RelativeLayout会调用它的onInterceptTouchEvent方法判断是否要拦截下这个事件,然后自己处理。如果返回true那个执行RelativeLayout的onTouchEvent方法,如果返回false那么这条传递链就继续向下延伸到RelativeLayout的子View –TextView的dispatchTouchEvent,由于TextView已经不能够有子View了,不能够再向下传递,dispatchTouchEvent再将事件分发到TextView的onTouchEvent方法,onTouchEvent返回true或者false:

1)     如果onTouchEvent返回true,表示TextView能够处理该事件,那么事件就不再传递下去,后续的事件(ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP,ACTION_UP)都会按照同样的传递过程进行传递,最后交给TextView的onTouchEvent方法进行处理。

2)     如果onTouchEvent返回false,表示TextView不能够处理该事件,这时事件就会发生回传,传递给其父View– RelativeLayout的onTouchEvent方法,如果onTouchEvent方法返回true,表示RelativeLayout可以处理该事件,那么后续的事件传递到RelativeLayout的onInterceptTouchEvent方法的时候就会拦截下来直接由RelativeLayout的onTouchEvent进行处理;如果onTouchEvent方法返回false,那么事件继续进行上传到Activity的OnTouchEvent,如果返回true由它进行处理,如果返回false,由于它已经是最顶层了,事件传递到此为止,Touch事件无效。

说了这么多,不如来一幅生动形象的图来描述整个的Touch事件传递过程吧。

Android事件分发机制完全解析(终极版二)_第2张图片

上面两幅图分别表现的是1)和2)的事件传递图,实线表示ACTION_DOWN事件的传递,虚线表示后续其它事件的传递。第一张图中TextView的onTouchEvent处理该事件,那么第二次仍然按照原路传递到TextView由它进行处理;第二张图中TextView的onTouchEvent不能处理该事件,那么就回传到RelativeLayout的onTouchEvent进行处理,可以处理便不进行回传,后续其它事件再传递,传递到RelativeLayout就由它来进行处理,不需要再向下传递。

到这里Touch事件传递机制的说明就算完成了。但Touch事件仍有很多让人疑惑不解的, 比如ACTION_MOVE拖动的方向距离是如何实现的, ACTION_POINTER_UP, ACTION_POINTER_DOWN有是如何实现的。下面在对它们进行简要的讲解。

ACTION_MOVE拖动方向距离是通过MotionEvent的getX() getY(), getRawX()getRawY 这四个方法得到的。这里值得一提的是前面两个方法是得到的是相对于当前Widget左上角的X, Y坐标,而后面两个方法得到的是以手机屏幕左上角为原点的X, Y      坐标。既然得到了当前坐标那么拖动的距离方向就很好计算了,通过当前ACTION_MOVE事件得到的X,Y坐标减去上一个事件(可能是ACTION_DOWN也可能是ACTION_MOVE)得到的X, Y坐标就可以得知拖动的方向距离了。

而ACTION_POINTER_UP,ACTION_POINTER_DOWN的实现则是通过方法getX(pointerIndex)实现的,pointerIndex表示的就是屏幕上面的点,这样我们就可以知道屏幕上的每个点的当前坐标了。

你可能感兴趣的:(Android)