Tangani isyarat multisentuh

Mencoba cara Compose
Jetpack Compose adalah toolkit UI yang direkomendasikan untuk Android. Pelajari cara menggunakan sentuhan dan input di Compose.

Gestur multi-sentuh adalah saat beberapa pointer (jari) mengetuk layar secara bersamaan. Dokumen ini menjelaskan cara mendeteksi gestur yang melibatkan beberapa pointer.

Melacak beberapa pointer

Saat beberapa pointer mengetuk layar secara bersamaan, sistem akan menghasilkan peristiwa sentuhan berikut:

  • ACTION_DOWN: dikirim saat pointer pertama mengetuk layar. Langkah ini akan memulai gestur. Data pointer untuk pointer ini selalu berada di indeks 0 dalam MotionEvent.
  • ACTION_POINTER_DOWN: dikirim saat pointer tambahan masuk ke layar setelah pointer pertama. Anda dapat memperoleh indeks pointer yang baru saja turun menggunakan getActionIndex().
  • ACTION_MOVE: dikirim saat terjadi perubahan dalam gestur, yang melibatkan sejumlah penunjuk.
  • ACTION_POINTER_UP: dikirim saat pointer non-primer naik. Anda dapat memperoleh indeks pointer yang baru saja naik menggunakan getActionIndex().
  • ACTION_UP: dikirim saat pointer terakhir meninggalkan layar.
  • ACTION_CANCEL: menunjukkan bahwa seluruh gestur, termasuk semua penunjuk, dibatalkan.

Gestur awal dan akhir

Gestur adalah serangkaian peristiwa yang dimulai dengan peristiwa ACTION_DOWN dan diakhiri dengan peristiwa ACTION_UP atau ACTION_CANCEL. Hanya ada satu gestur aktif dalam satu waktu. Tindakan DOWN, MOVE, UP, dan CANCEL berlaku untuk seluruh gestur. Misalnya, peristiwa dengan ACTION_MOVE dapat menunjukkan gerakan semua penunjuk ke bawah pada saat itu.

Melacak pointer

Gunakan indeks dan ID pointer untuk melacak posisi setiap pointer dalam MotionEvent.

  • Indeks: MotionEvent menyimpan informasi pointer dalam array. Indeks pointer adalah posisinya di dalam array ini. Sebagian besar metode MotionEvent menggunakan indeks pointer sebagai parameter, bukan ID pointer.
  • ID: setiap pointer juga memiliki pemetaan ID yang tetap ada di semua peristiwa sentuhan untuk memungkinkan pelacakan pointer individual di seluruh gestur.

Pointer individual muncul dalam peristiwa gerakan dalam urutan yang tidak ditentukan. Dengan demikian, indeks pointer dapat berubah dari satu peristiwa ke peristiwa berikutnya, tetapi ID pointer dari suatu pointer dipastikan tetap konstan selama pointer tetap aktif. Gunakan metode getPointerId() untuk mendapatkan ID pointer guna melacak pointer di semua peristiwa gerakan berikutnya dalam gestur. Kemudian, untuk peristiwa gerakan berturut-turut, gunakan findPointerIndex() untuk mendapatkan indeks pointer untuk ID pointer yang diberikan dalam peristiwa gerakan tersebut. Contoh:

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);
    ...
}

Untuk mendukung beberapa pointer sentuh, Anda dapat menyimpan dalam cache semua pointer aktif dengan ID-nya pada waktu peristiwa ACTION_POINTER_DOWN dan ACTION_DOWN masing-masing. Hapus penunjuk dari cache Anda di peristiwa ACTION_POINTER_UP dan ACTION_UP-nya. Anda mungkin menganggap ID yang di-cache ini berguna untuk menangani peristiwa tindakan lainnya dengan benar. Misalnya, saat memproses peristiwa ACTION_MOVE, temukan indeks untuk setiap ID pointer aktif yang di-cache, ambil koordinat pointer menggunakan fungsi getX() dan getY(), lalu bandingkan koordinat ini dengan koordinat yang di-cache untuk mengetahui pointer mana yang bergerak.

Gunakan fungsi getActionIndex() dengan peristiwa ACTION_POINTER_UP dan ACTION_POINTER_DOWN saja. Jangan gunakan fungsi ini dengan peristiwa ACTION_MOVE, karena fungsi ini selalu menampilkan 0.

Mengambil tindakan MotionEvent

Gunakan metode getActionMasked() atau versi kompatibilitas MotionEventCompat.getActionMasked() untuk mengambil tindakan MotionEvent. Tidak seperti metode getAction() sebelumnya, getActionMasked() didesain untuk berfungsi dengan beberapa pointer. Tindakan ini akan menampilkan tindakan tanpa indeks pointer. Untuk tindakan dengan indeks pointer yang valid, gunakan getActionIndex() untuk mengembalikan indeks pointer yang terkait dengan tindakan seperti yang ditunjukkan dalam cuplikan berikut:

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 "";
}
Gambar 1. Pola gambar multi-sentuh.

Referensi lainnya

Untuk mengetahui informasi selengkapnya terkait peristiwa input, lihat referensi berikut: