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です。

サンプルコード

    @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にあたります)。

サンプルコードの出力例

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