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

تجربة طريقة الإنشاء
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. تتوفّر إيماءة نشطة واحدة في كل مرة. تسري الإجراءات "أسفل" و"تحريك" و"لأعلى" و"إلغاء" على الإيماءة بالكامل. على سبيل المثال، يمكن أن يشير حدث مع 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. أنماط رسم تستند إلى نقاط اتصال متعددة.

مراجع إضافية

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