您的位置:首页 > 移动开发 > Android开发

关于 MotionEvent 的笔记

2016-05-05 20:36 633 查看

概述

MotionEvent 不仅仅用来表示 触摸事件, 还可以是 鼠标/trackball/pen 等等事件.

一个MotionEvent包含的信息: ACTION_DOWN 这种, 坐标, 压力, 大小, 方向.

两个相邻的 MotionEvent 的 时间间隔差不多是 10–40 ms 之间.

即, 这个时间段 其实也够了;

即 每秒种保证了 25—100 次的刷新, 即使ui上的更新, 也感觉比较顺滑的了.

关于pointerId和pointerIndex

每一个MotionEvent 都 包含了 当前所有 触摸点(Pointer)的信息—-即使它没有动.

即如果有多个手指在屏幕上面, 即使只有一个手指动, 但是这个MotionEvent中包含了所有的pointer的信息(坐标/压力等).

有两个不同的东西:

pointerId

在一个pointer的down到up之间, 其值恒定;

其值可能会大于 pointers的总数;

因为中途可能会有pointer离开, 其对应的pointerId就空了(当然可能会被新down下去的pointer拿去用);

pointerId失效后, 可能会被新down下去的pointer拿去用.

pointerIndex

一个pointer在down到up之间时, 其pointerIndex值是可能会有变化的.

比如, 总共有4个pointers.

一个pointer的pointerIndex为3,

但此时pointerIndex为1的手指up了, 那么总共变成了3个pointers了,

此时这个pointer的pointerIndex可能就会被调整为2了.

关于pointerId

每一个触摸点 都有一个 pointerid—-这个是唯一的, 一直有效的.(但在up/pointer_up后会失效, 可能会别新按下去的手指拿去)

获取 pointerId 的办法:

int getPointerId(int pointerIndex)//参数是0什么的, 最大为: int getPointerCount()-1
----注意, 在每一个gesture中, 一个手指的 pointerIndex 可能会不同, 但在 pointerId 却是一样的.
一个 pointerId 的有效期: 从这个手指 down/pointer_down 到 up/pointer_up 这一段时间之内.
注意: pointerId 也是按 0,1,2,3...之类的序号排下去的.
一个手指的pointerId 在 up/pointer_up 后就无效了,
其可能会被 其它新 按下去的 手指拿去用.
----这个要注意!
----即 pointerId 并非在 一个gesture 中一直唯一表明某一个手指的,
而仅仅是指 一个手指down/pointer_down 到 up/pointer_up 这一段时间之内 的id值.


关于pointerIndex

pointerIndex 则是从0–getPointerCount() 之间;

一个 pointer 的 index 其 会随着 情况的变化而变化, —-即不恒定.

比如,

总共有4个pointers.

一个pointer的pointerIndex为3,

但此时pointerIndex为1的手指up了, 那么总共变成了3个pointers了,

此时这个pointer的pointerIndex可能就会被调整为2了.

以下这些方法的参数用的都是 pointerIndex, 而不是 pointer id:

getX(int),
getY(int),
getAxisValue(int),
getPointerId(int),  //参数是pointerIndex, 返回的是 pointerId
getToolType(int)


关于 pointerIndex 和 pointerId 之间的转换:

方法: getPointerId(int) , 我们通过 pointer index 来得到这个 pointer的id

方法: findPointerIndex(int) , 我们可以 通过 pointer id 得到 其 index.

列几个重要的方法吧(有些前面已列过了)

如下:

int getPointerCount()
int getPointerId(int pointerIndex)
int findPointerIndex(int pointerId)
int getPointerId(int pointerIndex)
int getPointerIdBits()
这个方法是, 拿到当前这个MotionEvent的所有手指的id号.----这些id号 按位运算 放到 一个 int数据中.
比如, 有3个手指, 其对应的id为 2,3,5, 则返回的是  0000 0000 0010 1100, 即, 0x2c了.
----注意的是 pointerId 其实很朴素, 就是0, 1, 2, 3.....之类排下去的.


关于 Action 和 ActionMask 和 ActionIndex:

关于Action的简述:

内部用于标注事件类型的方式是:—-有一个int型数据用于记录 一个pointer的pointerIndex和action.

低版本直接做为MotionEvent的数据成员:

private int mAction;


高版本MotionEvent中需要通过jni来查询:

private static native int nativeGetAction(long nativePtr)


这个 int 型数据 实现上只用到了 低两位, 比如:

0x0101 ---- 高8位, 表示 pointerIndex
低8位, 表示 事件类型, ACTION_DOWN/ACTION_UP/ACTION_POINTER_DOWN 之类.


相关几个方法:

int getAction()
返回的 0x0101 这种.
int getActionMasked()
返回的是 低8位, 即 事件类型, ACTION_DOWN/ACTION_UP/ACTION_POINTER_DOWN 之类.
int getActionIndex()
返回的是 高8位, 即pointerIndex.
发生了 ACTION_POINTER_DOWN 和 ACTION_POINTER_UP 的 pointer 的 index.


内部标识位 的 详解:

action 类型:

public static final int ACTION_MASK             = 0xff; //用于获取低8位.

public static final int ACTION_DOWN             = 0;
public static final int ACTION_UP               = 1;
public static final int ACTION_MOVE             = 2;
public static final int ACTION_CANCEL           = 3;
public static final int ACTION_OUTSIDE          = 4;
public static final int ACTION_POINTER_DOWN     = 5;
public static final int ACTION_POINTER_UP       = 6;
public static final int ACTION_HOVER_MOVE       = 7;
public static final int ACTION_SCROLL           = 8;
public static final int ACTION_HOVER_ENTER      = 9;
public static final int ACTION_HOVER_EXIT       = 10;


pointerIndex:

public static final int ACTION_POINTER_INDEX_MASK  = 0xff00; //用于获取低2字节中的高8位.
public static final int ACTION_POINTER_INDEX_SHIFT = 8; //因为要从高8位移到低8位.

以下这些都过时了----而且是错的, 不要按这个来了.
public static final int ACTION_POINTER_1_DOWN   = ACTION_POINTER_DOWN | 0x0000; = 0x0005;
public static final int ACTION_POINTER_2_DOWN   = ACTION_POINTER_DOWN | 0x0100; = 0x0105;
public static final int ACTION_POINTER_3_DOWN   = ACTION_POINTER_DOWN | 0x0200; = 0x0205;
public static final int ACTION_POINTER_1_UP     = ACTION_POINTER_UP | 0x0000; = 0x0006;
public static final int ACTION_POINTER_2_UP     = ACTION_POINTER_UP | 0x0100; = 0x0106;
public static final int ACTION_POINTER_3_UP     = ACTION_POINTER_UP | 0x0200; = 0x0206;
public static final int ACTION_POINTER_ID_MASK  = 0xff00;
public static final int ACTION_POINTER_ID_SHIFT = 8;


注意一点:

ACTION_DOWN 的点 离开时 可能是以 ACTION_POINTER_UP 离开

—-因为可能并不是最后一个点离开的.

而 ACTION_POINTER_DOWN 的点, 可能以 ACTION_UP 离开的

—-因为虽然并不是第0个点按下去, 但可能是最后一个点离开的.

所以, * getAction 拿到的 ACTION_UP 并不总是 第0个按下去点的 离开事件.*

关于 Batch

概述:

由于, 我们每次通过 MotionEvent 的去处理 多点触摸事件, 很麻烦:

int getPointerCount()
int getPointerId(int pointerIndex)
int findPointerIndex(int pointerId)
int getPointerId(int pointerIndex)


所以, 思路上: 将 多个 motion event 放到一个 MotionEvent中.

—-即 批处理 的思想.

—-注意:

这个 批处理 只在 事件类型为 ACTION_MOVE 时 才有的,

而 ACT
990f
ION_DOWN/ACTION_UP/ACTION_CANCEL/ACTION_POINTER_DOWN/ACTION_POINTER_UP 都是没有的.

详述:

一个 MotionEvent 中包含的事件有:

最后一个motion event事件 + getHistorySize个历史 motion event事件.

这个方法, 注意一下:

float nativeGetAxisValue(long nativePtr, int axis, int pointerIndex, int historyPos)


涉及的方法有:

float getX()
本质是: nativeGetAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
即, 返回的是 **第0个手指** **最后一个**motion event 的x轴位置,
float getX(int pointerIndex)
本质是: nativeGetAxisValue(mNativePtr, AXIS_X, pointerIndex, HISTORY_CURRENT);
即, 返回的是 **第pointerIndex个** 手指 **最后一个**motion event 的x轴位置.

float getHistoricalX(int pointerIndex, int pos)
本质是: nativeGetAxisValue(mNativePtr, AXIS_X, pointerIndex, pos);
即, 返回的是 第pointerIndex个 手指 第pos个 motion event 的x轴位置.

final long getHistoricalEventTime(int pos)
----这里我就不多贴出来了, 实际上, 不仅仅可以 获得历史 motion event 的 坐标/时,
还可以 获得 压力 等等信息.
这里就不多说了.

int getHistorySize()
获得 这个 MotionEvent 中 包含了多少个 历史motion event事件.
只有当 事件类型为 ACTION_MOVE 时, 其返回才不为0; 否则返回0.


处理示例:

void printSamples(MotionEvent ev) {
final int historySize = ev.getHistorySize();
final int pointerCount = ev.getPointerCount();
for (int h = 0; h < historySize; h++) {
System.out.printf("At time %d:", ev.getHistoricalEventTime(h));
for (int p = 0; p < pointerCount; p++) {
System.out.printf("  pointer %d: (%f,%f)",
ev.getPointerId(p), ev.getHistoricalX(p, h), ev.getHistoricalY(p, h));
}
}
System.out.printf("At time %d:", ev.getEventTime());
for (int p = 0; p < pointerCount; p++) {
System.out.printf("  pointer %d: (%f,%f)",
ev.getPointerId(p), ev.getX(p), ev.getY(p));
}
}
注意:
先处理 历史motion event事件(序号越为0, 时间就越早),
最后 再来处理 最近的 motion event事件.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 触摸事件