マルチタッチ ジェスチャーは、複数のポインタ(指)で同時に画面をタップすることです。このドキュメントでは、複数のポインタを含む操作を検出する方法について説明します。
複数のポインタのトラッキング
複数のポインタが同時に画面をタップすると、システムは次のタッチイベントを生成します。
ACTION_DOWN
: 最初のポインタが画面をタップすると送信されます。これで操作が開始されます。このポインタのポインタデータは、常にMotionEvent
のインデックス0
にあります。ACTION_POINTER_DOWN
: 最初のポインタの後に追加のポインタが画面に入ったときに送信されます。ダウンしたばかりのポインタのインデックスは、getActionIndex()
を使用して取得できます。ACTION_MOVE
: 任意の数のポインタが関係して、操作で変更が発生すると送信されます。ACTION_POINTER_UP
: 非プライマリ ポインタが起動すると送信されます。最近出たポインタのインデックスは、getActionIndex()
を使用して取得できます。ACTION_UP
: 最後のポインタが画面から出ると送信されます。ACTION_CANCEL
: すべてのポインタを含む操作全体がキャンセルされることを示します。
開始と終了のジェスチャー
ジェスチャーとは、ACTION_DOWN
イベントで始まり、ACTION_UP
イベントまたは ACTION_CANCEL
イベントで終わる一連のイベントです。一度に実行できる操作は 1 つのみです。下、移動、上、キャンセルのアクションは、ジェスチャー全体に適用されます。たとえば、ACTION_MOVE
を含むイベントは、その時点でのすべてのポインタの下移動を示すことができます。
ポインタを追跡する
ポインタのインデックスと ID を使用して、MotionEvent
内の個々のポインタの位置をトラッキングします。
- インデックス:
MotionEvent
はポインタ情報を配列に格納します。ポインタのインデックスは、この配列内の位置です。ほとんどのMotionEvent
メソッドは、ポインタ ID ではなく、ポインタ インデックスをパラメータとして受け取ります。 - ID: 各ポインタには ID マッピングもあります。このマッピングはタッチイベント全体で持続し、操作全体で個々のポインタをトラッキングできるようにします。
個々のポインタは、未定義の順序でモーション イベント内に表示されます。したがって、ポインタのインデックスはあるイベントから次のイベントに変わる可能性があります。ただし、ポインタのポインタ ID は、ポインタがアクティブである限り一定に保たれます。getPointerId()
メソッドを使用してポインタの ID を取得し、操作の後続のすべてのモーション イベントでポインタをトラッキングします。連続するモーション イベントについては、findPointerIndex()
メソッドを使用して、そのモーション イベントの特定のポインタ ID のポインタ インデックスを取得します。次に例を示します。
Kotlin
private var mActivePointerId: Int = 0 override fun onTouchEvent(event: MotionEvent): Boolean { ... // Get the pointer ID. mActivePointerId = event.getPointerId(0) // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position. val (x: Float, y: Float) = event.findPointerIndex(mActivePointerId).let { pointerIndex -> // Get the pointer's current position. event.getX(pointerIndex) to event.getY(pointerIndex) } ... }
Java
private int mActivePointerId; public boolean onTouchEvent(MotionEvent event) { ... // Get the pointer ID. mActivePointerId = event.getPointerId(0); // ... Many touch events later... // Use the pointer ID to find the index of the active pointer // and fetch its position. int pointerIndex = event.findPointerIndex(mActivePointerId); // Get the pointer's current position. float x = event.getX(pointerIndex); float y = event.getY(pointerIndex); ... }
複数のタッチポインタをサポートするには、すべてのアクティブなポインタとそれぞれの ACTION_POINTER_DOWN
および ACTION_DOWN
イベント時刻の ID をキャッシュに保存します。ACTION_POINTER_UP
イベントと ACTION_UP
イベントでキャッシュからポインタを削除します。キャッシュに保存された ID は、他のアクション イベントを正しく処理するのに役立ちます。たとえば、ACTION_MOVE
イベントを処理する場合、キャッシュに保存されたアクティブなポインタ ID ごとにインデックスを見つけ、getX()
関数と getY()
関数を使用してポインタの座標を取得してから、これらの座標をキャッシュに保存された座標と比較することで、移動されたポインタを検出します。
getActionIndex()
関数は、ACTION_POINTER_UP
イベントと ACTION_POINTER_DOWN
イベントでのみ使用します。常に 0
が返されるため、この関数を ACTION_MOVE
イベントと一緒に使用しないでください。
MotionEvent
アクションを取得する
MotionEvent
のアクションを取得するには、getActionMasked()
メソッドまたは互換バージョン MotionEventCompat.getActionMasked()
を使用します。前述の getAction()
メソッドとは異なり、getActionMasked()
は複数のポインタで動作するように設計されています。ポインタ インデックスなしでアクションを返します。有効なポインタ インデックスを持つアクションの場合は、次のスニペットに示すように、getActionIndex()
を使用して、アクションに関連付けられたポインタのインデックスを返します。
Kotlin
val (xPos: Int, yPos: Int) = MotionEventCompat.getActionMasked(event).let { action -> Log.d(DEBUG_TAG, "The action is ${actionToString(action)}") // Get the index of the pointer associated with the action. MotionEventCompat.getActionIndex(event).let { index -> // The coordinates of the current screen contact, relative to // the responding View or Activity. MotionEventCompat.getX(event, index).toInt() to MotionEventCompat.getY(event, index).toInt() } } if (event.pointerCount > 1) { Log.d(DEBUG_TAG, "Multitouch event") } else { // Single touch event. Log.d(DEBUG_TAG, "Single touch event") } ... // Given an action int, returns a string description. fun actionToString(action: Int): String { return when (action) { MotionEvent.ACTION_DOWN -> "Down" MotionEvent.ACTION_MOVE -> "Move" MotionEvent.ACTION_POINTER_DOWN -> "Pointer Down" MotionEvent.ACTION_UP -> "Up" MotionEvent.ACTION_POINTER_UP -> "Pointer Up" MotionEvent.ACTION_OUTSIDE -> "Outside" MotionEvent.ACTION_CANCEL -> "Cancel" else -> "" } }
Java
int action = MotionEventCompat.getActionMasked(event); // Get the index of the pointer associated with the action. int index = MotionEventCompat.getActionIndex(event); int xPos = -1; int yPos = -1; Log.d(DEBUG_TAG,"The action is " + actionToString(action)); if (event.getPointerCount() > 1) { Log.d(DEBUG_TAG,"Multitouch event"); // The coordinates of the current screen contact, relative to // the responding View or Activity. xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } else { // Single touch event. Log.d(DEBUG_TAG,"Single touch event"); xPos = (int)MotionEventCompat.getX(event, index); yPos = (int)MotionEventCompat.getY(event, index); } ... // Given an action int, returns a string description public static String actionToString(int action) { switch (action) { case MotionEvent.ACTION_DOWN: return "Down"; case MotionEvent.ACTION_MOVE: return "Move"; case MotionEvent.ACTION_POINTER_DOWN: return "Pointer Down"; case MotionEvent.ACTION_UP: return "Up"; case MotionEvent.ACTION_POINTER_UP: return "Pointer Up"; case MotionEvent.ACTION_OUTSIDE: return "Outside"; case MotionEvent.ACTION_CANCEL: return "Cancel"; } return ""; }
参考情報
入力イベントの詳細については、次のリファレンスをご覧ください。