ژست های چند لمسی را مدیریت کنید

روش نوشتن را امتحان کنید
Jetpack Compose ابزار رابط کاربری پیشنهادی برای اندروید است. یاد بگیرید که چگونه از لمس و ورودی در Compose استفاده کنید.

یک حرکت چند لمسی زمانی است که چندین اشاره‌گر (انگشت) به طور همزمان روی صفحه نمایش ضربه می‌زنند. این سند نحوه تشخیص حرکاتی را که شامل چندین اشاره‌گر هستند، شرح می‌دهد.

چندین اشاره‌گر را دنبال کنید

وقتی چندین اشاره‌گر به طور همزمان روی صفحه نمایش ضربه می‌زنند، سیستم رویدادهای لمسی زیر را ایجاد می‌کند:

  • ACTION_DOWN : زمانی ارسال می‌شود که اولین اشاره‌گر روی صفحه ضربه می‌زند. این ژست حرکتی را شروع می‌کند. داده‌های اشاره‌گر برای این اشاره‌گر همیشه در اندیس 0 در MotionEvent قرار دارند.
  • ACTION_POINTER_DOWN : زمانی ارسال می‌شود که اشاره‌گرهای اضافی بعد از اشاره‌گر اول وارد صفحه می‌شوند. می‌توانید با استفاده از getActionIndex() ‎ اندیس اشاره‌گری که به پایین رفته است را بدست آورید.
  • ACTION_MOVE : زمانی ارسال می‌شود که تغییری در یک حرکت (gesture) رخ دهد، که شامل هر تعداد اشاره‌گر باشد.
  • ACTION_POINTER_UP : زمانی ارسال می‌شود که یک اشاره‌گر غیر اصلی به سمت بالا حرکت می‌کند. می‌توانید با استفاده از getActionIndex() اندیس اشاره‌گری که به سمت بالا حرکت کرده است را بدست آورید.
  • ACTION_UP : زمانی ارسال می‌شود که آخرین اشاره‌گر از صفحه نمایش خارج شود.
  • ACTION_CANCEL : نشان می‌دهد که کل حرکت، شامل همه اشاره‌گرها، لغو می‌شود.

حرکات شروع و پایان

یک حرکت، مجموعه‌ای از رویدادها است که با رویداد ACTION_DOWN شروع شده و با رویداد ACTION_UP یا ACTION_CANCEL پایان می‌یابد. در هر زمان یک حرکت فعال وجود دارد. اقدامات DOWN، MOVE، UP و CANCEL برای کل حرکت اعمال می‌شوند. به عنوان مثال، یک رویداد با ACTION_MOVE می‌تواند حرکت همه اشاره‌گرها به سمت پایین را در آن لحظه نشان دهد.

اشاره‌گرها را پیگیری کنید

از اندیس و شناسه‌ی اشاره‌گر برای پیگیری موقعیت‌های تک تک اشاره‌گرها در یک MotionEvent استفاده کنید.

  • اندیس (Index) : یک MotionEvent اطلاعات اشاره‌گر را در یک آرایه ذخیره می‌کند. اندیس یک اشاره‌گر، موقعیت آن در این آرایه است. اکثر متدهای MotionEvent اندیس اشاره‌گر را به عنوان پارامتر می‌گیرند، نه شناسه اشاره‌گر را.
  • شناسه (ID) : هر اشاره‌گر همچنین دارای یک نگاشت شناسه (ID mapping) است که در طول رویدادهای لمسی ثابت می‌ماند تا امکان ردیابی یک اشاره‌گر منفرد را در کل حرکت فراهم کند.

اشاره‌گرهای منفرد در یک رویداد حرکتی به ترتیب نامشخصی ظاهر می‌شوند. بنابراین، اندیس یک اشاره‌گر می‌تواند از یک رویداد به رویداد بعدی تغییر کند، اما شناسه اشاره‌گر یک اشاره‌گر تا زمانی که اشاره‌گر فعال باشد، ثابت می‌ماند. از متد getPointerId() برای بدست آوردن شناسه یک اشاره‌گر استفاده کنید تا اشاره‌گر را در تمام رویدادهای حرکتی بعدی در یک حرکت ردیابی کنید. سپس، برای رویدادهای حرکتی متوالی، از متد findPointerIndex() برای بدست آوردن اندیس اشاره‌گر برای یک شناسه اشاره‌گر داده شده در آن رویداد حرکتی استفاده کنید. به عنوان مثال:

کاتلین

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

جاوا

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 جداگانه، ذخیره کنید. اشاره‌گرها را در رویدادهای ACTION_POINTER_UP و ACTION_UP از حافظه پنهان خود حذف کنید. ممکن است این شناسه‌های ذخیره‌شده برای مدیریت صحیح سایر رویدادهای اکشن مفید باشند. به عنوان مثال، هنگام پردازش یک رویداد ACTION_MOVE ، اندیس هر شناسه اشاره‌گر فعال ذخیره‌شده را پیدا کنید، مختصات اشاره‌گر را با استفاده از توابع getX() و getY() بازیابی کنید، سپس این مختصات را با مختصات ذخیره‌شده خود مقایسه کنید تا متوجه شوید کدام اشاره‌گرها حرکت کرده‌اند.

از getActionIndex() فقط با رویدادهای ACTION_POINTER_UP و ACTION_POINTER_DOWN استفاده کنید. از این تابع با رویدادهای ACTION_MOVE استفاده نکنید، زیرا این تابع همیشه 0 را برمی‌گرداند.

بازیابی اکشن‌های MotionEvent

برای بازیابی اکشن یک MotionEvent از متد getActionMasked() یا نسخه سازگاری MotionEventCompat.getActionMasked() استفاده کنید. برخلاف متد getAction() قبلی، getActionMasked() برای کار با چندین اشاره‌گر طراحی شده است. این متد اکشن را بدون شاخص‌های اشاره‌گر برمی‌گرداند. برای اکشن‌هایی با شاخص اشاره‌گر معتبر، از getActionIndex() برای بازگرداندن شاخص اشاره‌گرهای مرتبط با اکشن، همانطور که در قطعه کد زیر نشان داده شده است، استفاده کنید:

کاتلین

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 -> ""
    }
}

جاوا

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 "";
}
شکل ۱. الگوهای طراحی چند لمسی.

منابع اضافی

برای اطلاعات بیشتر در مورد رویدادهای ورودی، به منابع زیر مراجعه کنید: