MotionEventでマルチタッチを検出する


MotionEventが改善され、ポインタIDが追加されました。IDで判別することで個々の指の動きを簡単に知ることができます。タッチイベントの検出・取得についてはタッチイベントを取得する(onTouchEventとMotionEvent)で解説しています。

マルチタッチの判別(ポインタIDの判別)

メソッド 概要
int getPointerCount() MotionEventでの通知ポインタ数(n)
int getPointerId(int pointerIndex) PointerIDの取得(Indexは0からn-1まで)
int findPointerIndex(int pointerId) PointerIDからポインタを特定する


MotionEventのマルチタッチ(PointerID関連)にかかわるメソッドの一部です。MotionEventについて詳細を把握されている場合、次の「MotionEvent通知タイミングと内容」を読み飛ばしても大丈夫です。「サンプルコード」を参照してください。
またAndroid 2.3から追加されたInputEventで入力デバイスが分かるようになっており、デバイス管理が改善されています(InputEventは改めて紹介予定)

MotionEvent通知タイミングと内容

MotionEventはタッチスクリーン、トラックボールなどのポインティングデバイスの動き、変化を検知してActivity,Viewなどに通知されるイベントです。ポインティングデバイスは各種デバイスで特性が異なるため、MotionEventは特性を吸収する役割も持っています。

MotionEvent.getAction()で取得できる動作

この中では ACTION_OUTSIDE が見慣れませんが、Viewの範囲外をタッチした場合に呼ばれます

定数名 説明
ACTION_DOWN 0x02 タッチ押下
ACTION_MOVE 0x00 指を持ち上げずにスライドさせた場合
ACTION_UP 0x01 指を持ち上げた場合
ACTION_CANCEL 0x03 UP+DOWNの同時発生(=キャンセル)の場合
ACTION_OUTSIDE 0x04 ターゲットとするUIの範囲外を押下

タッチスクリーン/タッチパネル

タッチスクリーンの場合はポインタ座標をX/Yの(Pixelに対する)絶対位置で検知できます。
ジェスチャー(指、マウス、トラックボールなどの)での押下はACTION_DOWNモーションイベントが発行されます。
移動中はACTION_MOVE、ジェスチャの最後、指が離されたときに、
ACTION_UPもしくはジェスチャがキャンセルと(フレームワーク側が)見なしたときは、ACTION_CANCELを通知します

トラックボール/マウス

トラックボールでは、ポインタ座標はX/Yの相対座標(移動量)で検知しています。
回転でACTION_MOVEイベントが通知されます(移動量)、タッチスクリーンと同様に押下でACTION_DOWN、
離したときにACTION_UPです。

サンプルコード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d("TouchEvent", "X:" + event.getX() + ",Y:" + event.getY());
 
 
    int historySize = event.getHistorySize();   //ACTION_MOVEイベントの数
    int pointerCount = event.getPointerCount();
 
    //イベントの発生時刻
    Log.d("TouchEvent", "event time: "+ event.getEventTime());
 
    //ポインタIDの取得、ポインタ座標
    for (int p = 0; p < pointerCount; p++) {
        Log.d("TouchEvent", "Pointer ID :"+ event.getPointerId(p) +
                " X " + event.getX(p) + " , " +
                 "Y " + event.getY(p) + " , " );
    }
 
    //イベント履歴
    for (int h = 0; h < historySize; h++) {
        Log.d("TouchEventHist", "event time: "+ event.getHistoricalEventTime(h));
        for (int p = 0; p < pointerCount; p++) {
            Log.d("TouchEventHist", "Pointer ID :"+ event.getPointerId(p) +
                    " X " + event.getHistoricalX(p, h) + " , " +
                     "Y " + event.getHistoricalY(p, h) + " , " );
        }
    }
 
    return true;
}

ActivityのonTouchEventです。13行目では、getPointerIdでポインタIDを取得しています。
getX,getYメソッドにポインタIDを引数として渡して、座標を取得します。
23,24行目、イベント履歴の検出でも同様に第1引数をポインタIDで与えてポインタの座標を取得しています。

マルチタッチの判別(ポインタIDの判別)

メソッド 概要
int getPointerCount() MotionEventでの通知ポインタ数(n)
int getPointerId(int pointerIndex) PointerIDの取得(Indexは0からn-1まで)
int findPointerIndex(int pointerId) PointerIDからポインタを特定する


MotionEventのマルチタッチ(PointerID関連)メソッドです。ポインタIDを使えば次回のonTouchEvent以降も同じ動きを検出できます。
特定の動きを追いたいときはgetPointerIdメソッドでポインタIDを保持し、ポインタIDを引数にMotionEvent#findPointerIndexメソッドを利用すれば該当するPointerIndexがわかります(サンプルコードでの変数pにあたります)。

サンプルコードの出力例

1
2
3
4
12-13 22:01:07.736: DEBUG/TouchEvent(338): event time: 135563
12-13 22:01:07.736: DEBUG/TouchEvent(338): Pointer ID :0 X 97.0 , Y 309.0
12-13 22:01:07.745: DEBUG/TouchEventHist(338): event time: 135492
12-13 22:01:07.745: DEBUG/TouchEventHist(338): Pointer ID :0 X 96.0 , Y 306.0
3 Comments