תנועת מגע מתרחשת כאשר משתמש מניח אצבע אחת או יותר על מסך המגע והאפליקציה שלך מפרשת את דפוס המגע הזה כמחווה. יש יש שני שלבים לזיהוי תנועה:
- מתבצע איסוף של נתוני אירועי מגע.
- פירוש הנתונים כדי לקבוע אם הם עומדים בקריטריונים של התנועות שהאפליקציה תומכת בהן.
שיעורי AndroidX
הדוגמאות במסמך הזה כוללות את
GestureDetectorCompat
וגם
MotionEventCompat
הסוגים. הכיתות האלה נמצאות ב-AndroidX
ספרייה. יש להשתמש במחלקות AndroidX כשאפשר
במכשירים מוקדמים יותר.
MotionEventCompat
לא מחליף את
MotionEvent
בכיתה. במקום זאת, הוא מספק שיטות שימושיות סטטיות שאליהן מעבירים
אובייקט MotionEvent
כדי לקבל את הפעולה שמשויכת אליו
אירוע.
איסוף נתונים
כשמשתמש מניח אצבע אחת או יותר על המסך, הפעולה הזו מפעילה
התקשרות חזרה
onTouchEvent()
בתצוגה שמקבלת את אירועי המגע. לכל רצף של מגע
אירועים - כגון מיקום, לחץ, גודל והוספה של
אצבע – שמזוהה כתנועה, onTouchEvent()
הוא
הופעלו כמה פעמים.
התנועה מתחילה כשהמשתמש נוגע בפעם הראשונה במסך, וממשיכה
המערכת עוקבת אחר מיקום האצבע או האצבעות של המשתמש, ומסתיימת ב-
תיעוד האירוע האחרון של האצבע האחרונה של המשתמש שיצאה מהמסך.
במהלך האינטראקציה הזו, נשלח הMotionEvent
אל
onTouchEvent()
מספק את הפרטים של כל אינטראקציה. האפליקציה שלך
יכול להשתמש בנתונים שסופקו על ידי MotionEvent
כדי לקבוע אם
התנועה שחשובה לה.
תיעוד אירועי מגע של פעילות או תצוגה
כדי ליירט אירועי מגע ב-Activity
או
View
, ביטול הקריאה החוזרת של onTouchEvent()
.
קטע הקוד הבא משתמש
getAction()
כדי לחלץ את הפעולה שהמשתמש מבצע מהפרמטר event
.
הפעולה הזו מספקת את הנתונים הגולמיים שדרושים כדי לקבוע אם תנועה מסוימת חשובה לך
על מה שקרה.
Kotlin
class MainActivity : Activity() { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. override fun onTouchEvent(event: MotionEvent): Boolean { return when (event.action) { MotionEvent.ACTION_DOWN -> { Log.d(DEBUG_TAG, "Action was DOWN") true } MotionEvent.ACTION_MOVE -> { Log.d(DEBUG_TAG, "Action was MOVE") true } MotionEvent.ACTION_UP -> { Log.d(DEBUG_TAG, "Action was UP") true } MotionEvent.ACTION_CANCEL -> { Log.d(DEBUG_TAG, "Action was CANCEL") true } MotionEvent.ACTION_OUTSIDE -> { Log.d(DEBUG_TAG, "Movement occurred outside bounds of current screen element") true } else -> super.onTouchEvent(event) } } }
Java
public class MainActivity extends Activity { ... // This example shows an Activity. You can use the same approach if you are // subclassing a View. @Override public boolean onTouchEvent(MotionEvent event){ switch(event.getAction()) { case (MotionEvent.ACTION_DOWN) : Log.d(DEBUG_TAG,"Action was DOWN"); return true; case (MotionEvent.ACTION_MOVE) : Log.d(DEBUG_TAG,"Action was MOVE"); return true; case (MotionEvent.ACTION_UP) : Log.d(DEBUG_TAG,"Action was UP"); return true; case (MotionEvent.ACTION_CANCEL) : Log.d(DEBUG_TAG,"Action was CANCEL"); return true; case (MotionEvent.ACTION_OUTSIDE) : Log.d(DEBUG_TAG,"Movement occurred outside bounds of current screen element"); return true; default : return super.onTouchEvent(event); } }
הקוד הזה מפיק הודעות כמו ההודעה הבאה ב-Logcat בזמן שהמשתמש מקיש, נגיעות ו החזקה וגרירה:
GESTURES D Action was DOWN GESTURES D Action was UP GESTURES D Action was MOVE
עבור תנועות מותאמות אישית, תוכלו לבצע עיבוד משלכם לאירועים האלה כדי
כדי לקבוע אם הן מייצגות תנועה שצריך לטפל בה. אבל אם
המשתמשת בתנועות נפוצות כמו הקשה כפולה, מגע להחזיק, להניע וכן הלאה,
אפשר להשתמש
GestureDetector
בכיתה. בעזרת GestureDetector
יהיה לך קל יותר לזהות
תנועות מבלי לעבד את אירועי המגע הנפרדים בעצמך. הדבר
הסבר נוסף בנושא זמין במאמר זיהוי תנועות.
תיעוד אירועי מגע בתצוגה אחת
במקום onTouchEvent()
, אפשר לצרף
View.OnTouchListener
אובייקט לכל View
באמצעות הפונקציה
setOnTouchListener()
. כך ניתן להאזין לאירועי מגע בלי לסווג את הקוד המשני
View
קיים, כמו בדוגמה הבאה:
Kotlin
findViewById<View>(R.id.my_view).setOnTouchListener { v, event -> // Respond to touch events. true }
Java
View myView = findViewById(R.id.my_view); myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // Respond to touch events. return true; } });
היזהרו מיצירת אוזן המחזירה את הערך false
עבור
אירוע ACTION_DOWN
.
אם תעשו זאת, לא תתבצע קריאה למאזינים
ACTION_MOVE
והקבוצה
ACTION_UP
רצף של
אירועים. הסיבה לכך היא ש-ACTION_DOWN
הוא נקודת ההתחלה של כל המשתמשים
אירועי מגע.
אם יוצרים תצוגה מותאמת אישית, אפשר לשנות
onTouchEvent()
, כמו שתואר קודם.
זיהוי תנועות
Android מספק את המחלקה GestureDetector
לזיהוי נפוץ
תנועות. חלק מהתנועות הנתמכות כוללות
onDown()
,
onLongPress()
,
וגם
onFling()
.
אפשר להשתמש ב-GestureDetector
בשילוב עם
onTouchEvent()
שתוארה קודם לכן.
זיהוי כל התנועות הנתמכות
כשמייצרים אובייקט GestureDetectorCompat
, אחד
של הפרמטר הזה הוא מחלקה שמממשת
GestureDetector.OnGestureListener
גרפי. GestureDetector.OnGestureListener
מודיע למשתמשים כאשר
שמתרחש במגע ספציפי. כדי לאפשר את
אובייקט GestureDetector
כדי לקבל אירועים, לבטל את התצוגה או לשנות את התצוגה
שיטת onTouchEvent()
של הפעילות, ומעבירים את כל האירועים שנמדדו
למופע של המזהה.
בקטע הקוד הבא, ערך מוחזר של true
נפרדות של on<TouchEvent>
מציינים
אירוע המגע מטופל. הערך המוחזר של false
מעביר את האירועים כלפי מטה
דרך מקבץ התצוגות עד שהמגע יטופל בהצלחה.
אם תריצו את קטע הקוד הבא באפליקציית בדיקה, תוכלו להבין איך
פעולות מופעלות כאשר מקיימים אינטראקציה עם מסך המגע
פריטי התוכן של MotionEvent
הם לכל אירוע מגע. ואז אפשר לראות
כמה נתונים מופקים לאינטראקציות פשוטות.
Kotlin
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity(), GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { private lateinit var mDetector: GestureDetectorCompat // Called when the activity is first created. public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = GestureDetectorCompat(this, this) // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this) } override fun onTouchEvent(event: MotionEvent): Boolean { return if (mDetector.onTouchEvent(event)) { true } else { super.onTouchEvent(event) } } override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } override fun onLongPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onLongPress: $event") } override fun onScroll( event1: MotionEvent, event2: MotionEvent, distanceX: Float, distanceY: Float ): Boolean { Log.d(DEBUG_TAG, "onScroll: $event1 $event2") return true } override fun onShowPress(event: MotionEvent) { Log.d(DEBUG_TAG, "onShowPress: $event") } override fun onSingleTapUp(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapUp: $event") return true } override fun onDoubleTap(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTap: $event") return true } override fun onDoubleTapEvent(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDoubleTapEvent: $event") return true } override fun onSingleTapConfirmed(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onSingleTapConfirmed: $event") return true } }
Java
public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String DEBUG_TAG = "Gestures"; private GestureDetectorCompat mDetector; // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener. mDetector = new GestureDetectorCompat(this,this); // Set the gesture detector as the double-tap // listener. mDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } @Override public void onLongPress(MotionEvent event) { Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); } @Override public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, float distanceY) { Log.d(DEBUG_TAG, "onScroll: " + event1.toString() + event2.toString()); return true; } @Override public void onShowPress(MotionEvent event) { Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); } @Override public boolean onSingleTapUp(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); return true; } @Override public boolean onDoubleTap(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); return true; } @Override public boolean onDoubleTapEvent(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); return true; } }
זיהוי קבוצת משנה של תנועות נתמכות
אם רוצים לעבד רק מספר קטן של תנועות, אפשר להאריך
GestureDetector.SimpleOnGestureListener
במקום ליישם את המדיניות GestureDetector.OnGestureListener
גרפי.
GestureDetector.SimpleOnGestureListener
מספק
להטמעה של כל
שיטות on<TouchEvent>
על ידי חזרה
false
לכולם. כך אפשר לשנות רק את השיטות
שחשובים לכם. לדוגמה, קטע הקוד הבא יוצר מחלקה שמתרחבת
GestureDetector.SimpleOnGestureListener
ושינויים מברירת המחדל
onFling()
וגם onDown()
בין אם אתם משתמשים ב-GestureDetector.OnGestureListener
או
GestureDetector.SimpleOnGestureListener
, שיטה מומלצת היא
מטמיעים שיטה onDown()
שמחזירה true
. הזה
כי כל התנועות מתחילות בהודעת onDown()
. אם
החזרת false
מ-onDown()
, כ
כברירת מחדל, המערכת של GestureDetector.SimpleOnGestureListener
מניח שאתם רוצים להתעלם משאר התנועה, ומהשיטות האחרות
לא ניתן להתקשר אל GestureDetector.OnGestureListener
. הדבר עלול לגרום
או בעיות לא צפויות. החזרת false
רק מ-
onDown()
אם רוצים להתעלם מתנועה שלמה.
Kotlin
private const val DEBUG_TAG = "Gestures" class MainActivity : Activity() { private lateinit var mDetector: GestureDetectorCompat public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mDetector = GestureDetectorCompat(this, MyGestureListener()) } override fun onTouchEvent(event: MotionEvent): Boolean { mDetector.onTouchEvent(event) return super.onTouchEvent(event) } private class MyGestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(event: MotionEvent): Boolean { Log.d(DEBUG_TAG, "onDown: $event") return true } override fun onFling( event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean { Log.d(DEBUG_TAG, "onFling: $event1 $event2") return true } } }
Java
public class MainActivity extends Activity { private GestureDetectorCompat mDetector; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDetector = new GestureDetectorCompat(this, new MyGestureListener()); } @Override public boolean onTouchEvent(MotionEvent event){ if (this.mDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } class MyGestureListener extends GestureDetector.SimpleOnGestureListener { private static final String DEBUG_TAG = "Gestures"; @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString() + event2.toString()); return true; } } }