MotionEvent

我们在Android进阶之绘图中介绍了如何在界面上进行绘制的部分,但是这仅仅是静态的画面,它属于输出部分,但是只有输出往往是不够的,还需要通过某种方式接收用户的输入,这才能构成交互。
在我们解除屏幕到离开屏幕会产生一系列触摸事件,要响应这些事件必须复写onTouchEvent(MotionEvent e):
这里传入的参数MotionEvent是一个很重要的参数,它包含了当前触摸点的坐标,以及触摸事件的类型:
当用户触摸屏的时候,就会触发onTouchEvent事件处理函数,每当位置发生改变的时候触发一次,当触摸结束的时候还会触发一次。
它有一个返回值如果当前的onTouchEvent已经处理了屏幕触摸,就返回true,否则,就返回false。从而通过View或者Activity堆栈来传递事件,直到成功处理触摸为止。这部分涉及到事件的传递和分发机制
在后面会详细介绍,我们先来认识下MotionEvent:

通过event.getAction() 可以获取事件的类型:
MotionEvent.ACTION_UP 触摸结束,ACTION_UP
MotionEvent.ACTION_DOWN 开始触摸,第一个手指头按下的时候触发
MotionEvent.ACTION_POINT_DOWN 其他手指再按下的时候触发
MotionEvent.ACTION_POINT_UP 其他手指抬起来的时候触发
MotionEvent.ACTION_MOVE 按下手指在屏幕上移动的时候
MotionEvent.ACTION_CANCEL 触摸事件取消的时候
MotionEvent.ACTION_OUTSIDE 移动操作发生在被监控的屏幕元素边界之外的时候

通过event.getX() event.getY() event.getRawX() event.getRawY() 可以分别获得当前触点距离父容器以及屏幕的坐标位置;这个可以在绘图介绍中的坐标体系中看到每个方法的返回值意义

还可以通过下面的方法获取到事件开始和结束的时间信息:
getDownTime() 事件开始时间
getEventTime() 事件结束时间

多点触控事件:

现在的电容屏一般都支持多点触控技术,判断当前触摸事件为单点触控还是多点触控可以使用getPointerCount()方法,如果大于1表示为多点触控。
多点触控每个点称为一个pointer,MotionEvent包含该时刻所有point的信息。每个point都有唯一的ID,这个ID是在该point刚触碰屏幕的时候赋值的。有效期至该点离开屏幕或者取消。
我们要获得每个点的信息,必须通过它的index,而要获得index必须使用ACTION_POINTER_ID_MASK从Action中获得Action Point id

多点触控的处理:

int xpos = -1;
int ypos = -1;
int action = event.getAction();
if(event.getPointerCount() >1) {
int actionPointerid = action & MotionEvent.ACTION_POINTER_ID_MASK;
int actionEvent = action & MotionEvent.ACTION_MASK;
int pointerIndex = event.findPointerIndex(actionPointerid);
xPos = (int)event.getX(pointerIndex);
yPos = (int)event.getY(pointerIndex);
}else {
xPos = (int)event.getX();
yPos = (int)event.getY();
}

跟踪触摸的移动:

每当当前的触摸接触位置,压力或者区域大小发生改变的时候,将会触发ACTION_MOVE。MotionEvent中包含有着这系列变化的历史值。可以使用如下方式获取历史值:

单点触控:
int historySize = event.getHistorySize();//返回当前事件可用的移动位置的数量
for(int i=0;i<historySize;i++){
float x = event.getHistoricalX(i);
float y = event.getHistoricalY(i);
}

多点触控:
int historySize = event.getHistorySize();//返回当前事件可用的移动位置的数量
for(int i=0;i<historySize;i++){
int id = event.getPointerId(i);
float x = event.getHistoricalX(id, i);
float y = event.getHistoricalY(id, i);
}

处理触摸屏移动事件:
处理移动事件一般首先处理每个历史事件,然后再处理当前的MotionEvent值

switch (action) {
case MotionEvent.ACTION_MOVE:
int historySize = event.getHistorySize();
for(int i=0;i<historySize;i++){
float x = event.getHistoricalX(i);
float y = event.getHistoricalY(i);
Log.i("MainActivity","历史坐标值:("+x+"),("+y+")");
}

float currentx = event.getX();
float currenty = event.getY();
Log.i("MainActivity","当前值:("+currentx+"),("+currenty+")");
Log.i("MainActivity", "ACTION_MOVE");
return true;
default:return super.onTouchEvent(event);
}

为控件添加触摸事件监听器:

可以使用setOnTouchLinstener方法为某个View对象监听触摸事件。

键盘事件:

除了上述的显示屏事件外Android中还提供了键盘事件的处理:
所有的硬件按键产生的事件都是由处于活动状态的Activity或者当前前台View进行处理。Android中控件在处理物理按键事件时,提供的回调方法有onKeyUp() ,onKeyDown(),onKeyLongPress()
要想让Activity或者View对按键的按下做出响应,需要重写onKeyDown和onKeyUp事件处理方法:
方法中的keyCode包含了被按下的键的值,把它和KeyEvent类中的静态的Keycode进行比较,就可以执行特定按键的处理。

要在Activity的View中对按键按下做出响应,需要实现OnKeyListener并使用setOnKeyListener方法将其分配给一个View。
OnKeyListener并不是为了单独的按键按下和释放分别实现独立的方法,而是使用单一的onKey事件。ACTION_DOWN表示按下按键,ACTION_UP表示释放按键

事件分发和事件拦截机制

上面所讲述的情况是相对理想的情况,也就是事件已经传送到当前的View的情形,但是一般一个View 往往都是处在某个ViewGroup中,这就引入了一个新的问题,事件是如何传递分发和拦截的。
我们先看下下面这张图:
绿色的代表一个View,它被layout在两个ViewGoup内,当一个事件发生的时候,首先从底层的父ViewGroup开始传输的,在介绍整个传输过程之前先介绍下面两个方法:

  • onInterceptTouchEvent()是用于事件的预处理并改变事件的传递方向,也就是决定是否允许Touch事件继续子控件传递,如果返回True表示事件在当前的viewGroup中会被处理,
    则向下传递被截断,所有子控件将没有机会参与Touch事件,同时把事件传递给当前的控件的onTouchEvent()处理;返回false,则把事件交给子控件的onInterceptTouchEvent()
    onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截.不能包含子view的控件是没有这个方法的.

  • onTouchEvent()这个上面介绍了用于处理事件,返回值决定当前控件是否消费了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向父控件传递,一但返回True,
    则父控件不用操心自己来处理Touch事件。返回false,则向上传递给父控件.

如果layoutview1,layoutview2 onInterceptTouchEvent都返回false,也就是不拦截,那么整个事件的传递如下图所示:

如果layoutview1 onInterceptTouchEvent 返回false ,layoutview2 onInterceptTouchEvent都返回true,那么整个事件的传递如下图所示:

如果layoutview1,layoutview2 onInterceptTouchEvent都返回false,也就是不拦截,childview onTouchEvent 返回true 那么整个事件的传递如下图所示:

Contents
  1. 1. MotionEvent
  2. 2. 多点触控事件:
  3. 3. 跟踪触摸的移动:
  4. 4. 为控件添加触摸事件监听器:
  5. 5. 键盘事件:
  6. 6. 事件分发和事件拦截机制