关于 MotionEvent 的笔记

来源:互联网 发布:手机淘宝店铺怎么开 编辑:程序博客网 时间:2024/05/21 22:26

概述

  • 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, 返回的是 pointerIdgetToolType(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 时 才有的,
      • 而 ACTION_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事件.
2 0