תנועת מגע מרובה היא תנועה שבה כמה מכשירים למעקב אחר תנועות (אצבעות) מקישים על המסך בו-זמנית. במסמך הזה נסביר איך לזהות תנועות שמערבות כמה מכשירים.
מעקב אחר כמה מצביעים
כשמספר מכשירים מקישים על המסך בו-זמנית, המערכת יוצרת את אירועי המגע הבאים:
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
מקבלות את אינדקס הסמן כפרמטר, במקום את מזהה הסמן. - מזהה: לכל סמן יש גם מיפוי מזהה שנשאר קבוע לאורך אירועי המגע, כדי לאפשר מעקב אחרי סמן ספציפי לאורך כל התנועה.
נקודות הצבעה נפרדות מופיעות באירוע תנועה בסדר לא מוגדר. לכן, האינדקס של מצביע יכול להשתנות מאירוע אחד למשנהו, אבל מזהה המצביע של מצביע מסוים יישאר קבוע כל עוד המצביע פעיל. משתמשים ב-method getPointerId()
כדי לקבל מזהה של סמן כדי לעקוב אחרי הסמן בכל אירועי התנועה הבאים בתנועה. לאחר מכן, באירועי תנועה רצופים, משתמשים ב-method 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
כדי לאחזר את הפעולה של MotionEvent
, משתמשים בשיטה getActionMasked()
או בגרסה התואמת MotionEventCompat.getActionMasked()
. בניגוד לשיטה הקודמת 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 ""; }
מקורות מידע נוספים
למידע נוסף בנושא אירועי קלט, אפשר לעיין במקורות המידע הבאים:
- סקירה כללית על אירועי קלט
- סקירה כללית על חיישנים
- איך הופכים תצוגה מותאמת אישית לאינטראקטיבית
- גרירה ושינוי קנה מידה