處理多點觸控手勢

試用 Compose
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中使用觸控和輸入功能。

多點觸控手勢是指有多個指標 (手指) 輕觸螢幕的位置 本文件說明如何偵測涉及的手勢 以便檢視多個指標

追蹤多個指標

如果有多個指標同時輕觸螢幕,系統會產生多個指標 下列觸控事件:

  • ACTION_DOWN: 在第一個指標輕觸螢幕時傳送。即可啟動手勢。 這個指標的指標資料一律會位於 0MotionEvent
  • ACTION_POINTER_DOWN: 額外的指標進入畫面後傳送。您可以取得 剛剛下降的指標索引 getActionIndex()
  • ACTION_MOVE: 在手勢發生變更時傳送,且 指標。
  • ACTION_POINTER_UP: 在非主要指標上升時傳送。您可以取得 剛剛使用 getActionIndex() 向上的指標。
  • ACTION_UP: 在最後一個指標離開螢幕畫面時傳送。
  • ACTION_CANCEL: 表示已取消整個手勢,包括所有指標。

開始和結束手勢

手勢是指一系列以 ACTION_DOWN 開頭的事件 事件,並在結尾為 ACTION_UPACTION_CANCEL 事件。一次只能啟用一個手勢。 「向下」、「移動」、「向上」和「取消」動作會套用到整個手勢。舉例來說 具有 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);
    ...
}

如要支援多個觸控指標,您可以使用 其 ID 必須位於個別 ACTION_POINTER_DOWN ACTION_DOWN事件時間。從 他的「ACTION_POINTER_UP」和「ACTION_UP事件」。您可能會 如要正確處理其他動作事件,這些快取的 ID 會有所幫助。適用對象 舉例來說,處理 ACTION_MOVE 事件時,請找出 每個快取的有效指標 ID 時,請使用 getX()getY() 函式,然後對照這些座標與快取的座標, 瞭解哪些指標會移動

getActionIndex() 函式與 ACTION_POINTER_UPACTION_POINTER_DOWN事件 。請勿將此函式與 ACTION_MOVE 事件搭配使用,因為這樣 一律傳回 0

擷取 MotionEvent 項動作

使用 getActionMasked() 方法或相容性版本 MotionEventCompat.getActionMasked() 擷取 MotionEvent 的動作。與先前的 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 "";
}
圖 1.多點觸控繪圖 。

其他資源

如要進一步瞭解輸入事件,請參閱以下資源 參考資料: