التعامل مع إيماءات اللمس المتعدد

تجربة طريقة ComposeAllowed
Jetpack Compose هي مجموعة أدوات واجهة المستخدم التي ننصح بها لنظام التشغيل Android. تعرَّف على كيفية استخدام اللمس والإدخال في ميزة "إنشاء".

يمكن استخدام إيماءة اللمس المتعدد عندما تنقر عدة مؤشرات (أصابع) على الشاشة في الوقت نفسه. يصف هذا المستند كيفية اكتشاف الإيماءات التي تتضمن مؤشرات متعددة.

تتبُّع مؤشرات متعددة

عند نقر عدة مؤشرات على الشاشة في الوقت نفسه، يُنشئ النظام أحداث اللمس التالية:

  • ACTION_DOWN: يتم إرساله عند نقر المؤشر الأول على الشاشة. يؤدي هذا الإجراء إلى بدء الإيماءة. تتوفّر دائمًا بيانات المؤشر لهذا المؤشر في الفهرس 0 في MotionEvent.
  • ACTION_POINTER_DOWN: يتم إرساله عند دخول مؤشرات إضافية إلى الشاشة بعد المؤشر الأول. يمكنك الحصول على فهرس المؤشر الذي انخفض للتو باستخدام getActionIndex().
  • ACTION_MOVE: يتم إرساله عند حدوث تغيير في إيماءة، ويشمل أي عدد من المؤشرات.
  • ACTION_POINTER_UP: يتم إرساله عند ارتفاع مؤشر غير أساسي يمكنك الحصول على فهرس المؤشر الذي ارتفع للتو باستخدام getActionIndex().
  • ACTION_UP: يتم إرساله عند خروج المؤشر الأخير من الشاشة.
  • ACTION_CANCEL: يشير إلى أنّه تم إلغاء الإيماءة بالكامل، بما في ذلك جميع المؤشرات.

إيماءات البدء والانتهاء

الإيماءة هي سلسلة من الأحداث تبدأ بحدث ACTION_DOWN وتنتهي بحدث ACTION_UP أو ACTION_CANCEL. يتم تنفيذ إيماءة واحدة نشطة في كل مرة. تنطبق الإجراءات "أسفل" و"نقل" و"لأعلى" و"إلغاء" على الإيماءة بأكملها. على سبيل المثال، يمكن أن يشير الحدث الذي يتضمّن ACTION_MOVE إلى حركة جميع المؤشرات الهابطة في هذه اللحظة.

تتبُّع المؤشرات

استخدِم فهرس المؤشر ورقم تعريفه لتتبّع مواضع المؤشرات الفردية في MotionEvent.

  • الفهرس: يخزِّن MotionEvent معلومات المؤشر في مصفوفة. فهرس المؤشر هو موضعه داخل هذه المصفوفة. تستخدم معظم طُرق MotionEvent فهرس المؤشر كمَعلمة، بدلاً من معرّف المؤشر.
  • رقم التعريف: يتضمّن كل مؤشر أيضًا عملية ربط معرّف تبقى ثابتة في جميع أحداث اللمس للسماح بتتبُّع مؤشر فردي على مستوى الإيماءة بالكامل.

تظهر المؤشرات الفردية ضمن حدث حركة بترتيب غير محدد. وبالتالي، يمكن أن يتغيّر فهرس المؤشر من حدث إلى آخر، ولكن مضمون المؤشر هو أن يظل ثابتًا ما دام المؤشر نشطًا. استخدِم طريقة getPointerId() للحصول على رقم تعريف المؤشر لتتبُّع كل أحداث الحركة اللاحقة بإيماءة. بعد ذلك، بالنسبة إلى أحداث الحركة المتتالية، استخدِم الطريقة findPointerIndex() للحصول على فهرس المؤشر لمعرّف مؤشر معيّن في حدث الحركة هذا. على سبيل المثال:

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. أزِل المؤشرات من ذاكرة التخزين المؤقت في حدثَي 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() لعرض فهرس المؤشرات المرتبطة بالإجراء كما هو موضّح في المقتطف التالي:

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. أنماط الرسم المتعددة اللمسات.

مصادر إضافية

لمزيد من المعلومات حول أحداث الإدخال، يمكنك الاطّلاع على المراجع التالية: