يمكن استخدام إيماءة اللمس المتعدد عندما تنقر عدة مؤشرات (أصابع) على الشاشة في الوقت نفسه. يصف هذا المستند كيفية اكتشاف الإيماءات التي تتضمن مؤشرات متعددة.
تتبُّع مؤشرات متعددة
عند نقر عدة مؤشرات على الشاشة في الوقت نفسه، يُنشئ النظام أحداث اللمس التالية:
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 ""; }
مصادر إضافية
لمزيد من المعلومات حول أحداث الإدخال، يمكنك الاطّلاع على المراجع التالية:
- نظرة عامة على أحداث الإدخال
- نظرة عامة على أدوات الاستشعار
- إنشاء طريقة عرض مخصّصة تفاعلية
- السحب والتعديل