系列文章:
安卓手势处理(一)view的位置信息
安卓手势处理(二) MotionEvent
安卓手势处理(三)之实现图片的放大和缩小
安卓手势处理(四)之Fling
安卓手势处理(五)案例
上一篇文章确定了view的位置,这一篇就来讲一下view是如何分辨多个手指的点击事件。
MotionEvent
事件的信息就是封装在MotionEvent这个类之中的,包含事件类型(Action),手指id(pointerId),手指索引(index),事件发生的坐标信息(x,y)。
获取事件坐标位置API:
getX() //获取相对于该view显示区域左上角的位置x
getY() //获取相对于该view显示区域左上角的位置y
getRawX() //获取相对于整个屏幕左上角的位置x
getRawY() //获取相对于整个屏幕左上角的位置y
获取事件类型API:
public final int getAction() {
return nativeGetAction(mNativePtr);
}
public final int getActionMasked() {
return nativeGetAction(mNativePtr) & ACTION_MASK;
}
上面两个API的区别就是有没有ACTION_MASK,ACTION_MASK=0xff,说明最低的八位表示事件类型,常用的事件类型有下面几种:
MotionEvent.ACTION_DOWN
MotionEvent.ACTION_POINTER_DOWN
MotionEvent.ACTION_UP
MotionEvent.ACTION_POINTER_UP
MotionEvent.ACTION_MOVE
MotionEvent.ACTION_CANCEL
具体意义就不解释了
MotionEvent还带有index信息,用以记录手指的index,这个参数是会变化的,同一个手指的index也会随着其他手指的抬起发生变化,然而手指的id是不会变化的,只要这个手指一直在屏幕上,那么id永远不会变化,这样就给我们一种方法用以监视某一个手指的行为,获取id的方法要先获取index:
int index = event.getActionIndex();
int id = event.getPointerId(index);
获取id对应的index:
public final int findPointerIndex(int pointerId) {
return nativeFindPointerIndex(mNativePtr, pointerId);
}
使用下面的例子来观察id和index的变化:
viewGroup.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getActionMasked();
int index = event.getActionIndex();
int id = event.getPointerId(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "ACTION_DOWN" + " index:" + index + "; id:" + id);
break;
case MotionEvent.ACTION_POINTER_DOWN:
Log.d(TAG, "ACTION_POINTER_DOWN" + " index:" + index + "; id:" + id);
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "ACTION_UP" + " index:" + index + "; id:" + id);
break;
case MotionEvent.ACTION_POINTER_UP:
Log.d(TAG, "ACTION_POINTER_UP" + " index:" + index + "; id:" + id);
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "ACTION_MOVE" + " index:" + index + "; id:" + id);
break;
default:
break;
}
return true;
}
});
假如A、B手指先后按下,那么此时的状态是这样的:
A id:0 index:0
B id:1 index:1
A手指抬起,此时状态:
B id:1 index:0
A手指再次按下:
A id:0 index:1
B id:1 index:0
B抬起:
A id:0 index:0
从log可以看出,index会动态变化,只要有其他手指抬起,比这个手指的index大的手指的index都会减小1,但是id是不变的。
还有一点要注意的是,MOVE事件的id总是0,因为MOVE事件是没有手指信息的,不知道为什么安卓没有封装,那么如果我只想监听第二根手指的轨迹,那该怎么办呢?
tv.setOnTouchListener(new View.OnTouchListener() {
int mOldX;
int mOldY;
boolean mSecondDown = false;
//监听第二根手指
int mObsever = 1;
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getActionMasked();
int index = event.getActionIndex();
int id = event.getPointerId(index);
int currX = (int) event.getRawX(index);
int currY = (int) event.getRawY(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
Log.d("HAHA", "ACTION_DOWN" + " index:" + index + "; id:" + id);
if (id == mObsever) {
mSecondDown = true;
mOldX = currX;
mOldY = currY;
}
break;
case MotionEvent.ACTION_MOVE:
Log.d("HAHA", "ACTION_MOVE" + " index:" + index + "; id:" + id);
if (mSecondDown) {
int x = (int) event.getRawX(event.findPointerIndex(mObsever));
int y = (int) event.getRawY(event.findPointerIndex(mObsever));
int offsetX = x - mOldX;
int offsetY = y - mOldY;
tv.setTranslationX(tv.getTranslationX() + offsetX);
tv.setTranslationY(tv.getTranslationY() + offsetY);
mOldX = x;
mOldY = y;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if(id == mObsever){
mSecondDown = false;
}
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
});
直接在MOVE事件中,获取到第id为1对应的index,然后根据index获取坐标,这样就完成了对任意一根手指事件的监听。