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

تجربة طريقة "الكتابة"
‫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() للحصول على موقع المؤشر لمعرّف مؤشر معيّن في مسجّل الحركات هذا. على سبيل المثال:

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

مراجع إضافية

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