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

امتحان کردن روش Compose
Jetpack Compose جعبه‌ابزار واسط کاربر توصیه‌شده برای Android است. با نحوه استفاده از لمس و ورودی در Compose آشنا شوید.

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

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

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

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

اشاره‌های شروع و پایان

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

ردیابی اشاره‌گرها

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

  • نمایه: MotionEvent اطلاعات اشاره‌گر را در آرایه ذخیره می‌کند. نمایه اشاره‌گر موقعیت آن در این آرایه است. بیشتر روش‌های MotionEvent نمایه اشاره‌گر را به‌عنوان پارامتر درنظر می‌گیرند، نه شناسه اشاره‌گر.
  • شناسه: هر اشاره‌گر همچنین دارای یک نگاشت شناسه است که در رویدادهای لمسی ثابت می‌ماند تا امکان ردیابی یک اشاره‌گر خاص در کل اشاره فراهم شود.

اشاره‌گرهای تکی در رویداد حرکتی با ترتیبی نامشخص ظاهر می‌شوند. بنابراین، نمایه اشاره‌گر می‌تواند از رویدادی به رویداد دیگر تغییر کند، اما شناسه اشاره‌گر تضمین می‌شود که تا زمانی که اشاره‌گر فعال است، ثابت بماند. از روش 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 کنش

از روش getActionMasked() یا نسخه سازگاری MotionEventCompat.getActionMasked() برای بازیابی کنش MotionEvent استفاده کنید. برخلاف روش قبلی 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 "";
}
شکل ۱. الگوهای طراحی چندلمسی.

منابع بیشتر

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