מושגים מרכזיים

אפשר לנסות את הדרך של כתיבת הודעה
‫Jetpack Compose היא ערכת הכלים המומלצת לבניית ממשק משתמש ב-Android. איך גוררים ומשחררים ב-Compose

בקטעים הבאים מוסברים כמה מושגים חשובים לגבי תהליך הגרירה וההדבקה.

תהליך הגרירה והשחרור

יש ארבעה שלבים או מצבים בתהליך הגרירה והשחרור: התחלה, המשך, שחרור וסיום.

התחיל

בתגובה לתנועת גרירה של משתמש, האפליקציה שלכם קוראת ל-startDragAndDrop() כדי להודיע למערכת להתחיל פעולת גרירה ושחרור. הארגומנטים של השיטה מספקים את הפרטים הבאים:

  • הנתונים שרוצים לגרור.
  • קריאה חוזרת (callback) לציור צללית גרירה
  • מטא-נתונים שמתארים את הנתונים שנגררו
  • המערכת מגיבה בקריאה חוזרת לאפליקציה כדי לקבל צל של גרירה. לאחר מכן, המערכת מציגה את צללית הגרירה במכשיר.
  • לאחר מכן, המערכת שולחת אירוע גרירה עם סוג הפעולה ACTION_DRAG_STARTED למאזין של אירוע הגרירה של כל האובייקטים View בפריסה הנוכחית. כדי להמשיך לקבל אירועי גרירה – כולל אירוע אפשרי של שחרור – פונקציית ה-event listener של הגרירה צריכה להחזיר true. הפעולה הזו רושמת את מאזין האירועים במערכת. רק משתמשי listener רשומים ממשיכים לקבל אירועי גרירה. בשלב הזה, המאזינים יכולים גם לשנות את המראה של אובייקט View היעד לגרירה כדי להראות שאפשר להוסיף אירוע גרירה לתצוגה.
  • אם מאזין אירועי הגרירה מחזיר false, הוא לא מקבל אירועי גרירה עבור הפעולה הנוכחית עד שהמערכת שולחת אירוע גרירה עם סוג הפעולה ACTION_DRAG_ENDED. החזרת הערך false על ידי ה-listener מציינת למערכת שהוא לא מעוניין בפעולת הגרירה וההעברה, ושהוא לא רוצה לקבל את הנתונים שנגררו.
התהליך נמשך…
המשתמש ממשיך לגרור. כשצל הגרירה חוצה את התיבה התוחמת של יעד השחרור, המערכת שולחת אירוע גרירה אחד או יותר אל פונקציית ה-event listener של הגרירה של היעד. יכול להיות שה-listener ישנה את המראה של אזור היעד View בתגובה לאירוע. לדוגמה, אם האירוע מציין שצללית הגרירה נכנסת לתיבה התוחמת של יעד השחרור – סוג הפעולה ACTION_DRAG_ENTERED – אפשר להגדיר את ה-listener כך שיגיב על ידי הדגשת View.
בוטל
המשתמש משחרר את צללית הגרירה בתוך התיבה התוחמת של יעד השחרור. המערכת שולחת ל-listener של אזור היעד של הגרירה אירוע גרירה עם סוג הפעולה ACTION_DROP. אובייקט אירוע הגרירה מכיל את הנתונים שמועברים למערכת בקריאה ל-startDragAndDrop() שמתחילה את הפעולה. המאזין אמור להחזיר למערכת ערך בוליאני true אם הוא מעבד את הנתונים שהועברו בהצלחה. : השלב הזה מתרחש רק אם המשתמש משחרר את הצללית של הגרירה בתוך תיבת התוחמת של View שהמאזין שלה רשום לקבלת אירועי גרירה (יעד השחרור). אם המשתמש משחרר את צללית הגרירה בכל מצב אחר, לא נשלח ACTION_DROPאירוע גרירה
.
הסתיים

אחרי שהמשתמש משחרר את צללית הגרירה, ואחרי שהמערכת שולחת

אם צריך, המערכת שולחת אירוע גרירה עם סוג הפעולה ACTION_DRAG_ENDED כדי לציין שפעולת הגרירה הסתיימה.ACTION_DROP הפעולה הזו מתבצעת בלי קשר למיקום שבו המשתמש משחרר את צללית הגרירה. האירוע נשלח לכל פונקציית listener שרשומה לקבלת אירועי גרירה, גם אם הפונקציה מקבלת גם את האירוע ACTION_DROP.

כל אחד מהשלבים האלה מתואר בפירוט בקטע פעולת גרירה ושחרור.

גרירת אירועים

המערכת שולחת אירוע גרירה בצורה של אובייקט DragEvent, שמכיל סוג פעולה שמתאר מה קורה בתהליך הגרירה וההשלכה. בהתאם לסוג הפעולה, האובייקט יכול להכיל גם נתונים אחרים.

פונקציות event listener של גרירה מקבלות את האובייקט DragEvent. כדי לקבל את סוג הפעולה, המאזינים מתקשרים למספר DragEvent.getAction(). יש שישה ערכים אפשריים שמוגדרים על ידי קבועים במחלקה DragEvent, שמתוארים בטבלה 1:

טבלה 1. סוגי פעולות של DragEvent

סוג הפעולה משמעות
ACTION_DRAG_STARTED האפליקציה קוראת ל-startDragAndDrop() ומקבלת צללית גרירה. אם המאזין רוצה להמשיך לקבל אירועי גרירה עבור הפעולה הזו, הוא צריך להחזיר למערכת את הערך הבוליאני true.
ACTION_DRAG_ENTERED צללית גרירה נכנסת לתיבה התוחמת של View של ה-drag event listener. זהו סוג הפעולה הראשון של האירוע שהמאזין מקבל כשצל הגרירה נכנס לתיבת התוחמת.
ACTION_DRAG_LOCATION אחרי אירוע ACTION_DRAG_ENTERED, צללית הגרירה עדיין נמצאת בתיבה התוחמת של View של drag event listener של הגרירה.
ACTION_DRAG_EXITED אחרי אירוע ACTION_DRAG_ENTERED ולפחות אירוע ACTION_DRAG_LOCATION אחד, הצללית של הגרירה עוברת אל מחוץ לתיבת התוחמת של View של מאזין אירועי הגרירה.
ACTION_DROP צללית הגרירה משתחררת מעל View של ה-drag event listener. סוג הפעולה הזה נשלח ל-listener של אובייקט View רק אם ה-listener מחזיר ערך בוליאני true בתגובה לאירוע הגרירה ACTION_DRAG_STARTED. סוג הפעולה הזה לא נשלח אם המשתמש משחרר את צללית הגרירה מעל רכיב שרכיב ה-listener שלו לא רשום, או אם המשתמש משחרר את צללית הגרירה מעל משהו שלא שייך לפריסה הנוכחית.View

המאזין מחזיר ערך בוליאני true אם הוא מעבד את הפעולה בהצלחה. אחרת, הפונקציה צריכה להחזיר את הערך false.

ACTION_DRAG_ENDED המערכת מסיימת את פעולת הגרירה וההזזה. לפני סוג הפעולה הזה לא חייב להופיע אירוע ACTION_DROP. אם המערכת שולחת ACTION_DROP, קבלת סוג הפעולה ACTION_DRAG_ENDED לא מרמזת שההסרה הצליחה. המאזין צריך לקרוא ל-getResult(), כמו שמוצג בטבלה 2, כדי לקבל את הערך שמוחזר בתגובה ל-ACTION_DROP. אם אירוע ACTION_DROP לא נשלח, הפונקציה getResult() מחזירה את הערך false.

אובייקט DragEvent מכיל גם את הנתונים והמטא-נתונים שהאפליקציה מספקת למערכת בקריאה ל-startDragAndDrop(). חלק מהנתונים תקפים רק לסוגים מסוימים של פעולות, כפי שמסוכם בטבלה 2. מידע נוסף על אירועים והנתונים שמשויכים אליהם זמין בקטע פעולת גרירה ושחרור.

טבלה 2. נתונים תקינים של DragEvent לפי סוג הפעולה

getAction()
value
getClipDescription()
value
getLocalState()
value
getX()
value
getY()
value
getClipData()
value
getResult()
value
ACTION_DRAG_STARTED ✓ ✓        
ACTION_DRAG_ENTERED ✓ ✓        
ACTION_DRAG_LOCATION ✓ ✓ ✓ ✓    
ACTION_DRAG_EXITED ✓ ✓        
ACTION_DROP ✓ ✓ ✓ ✓ ✓  
ACTION_DRAG_ENDED   ✓       ✓

השיטות DragEvent getAction(), describeContents(), writeToParcel(), ו-toString() תמיד מחזירות נתונים תקינים.

אם שיטה לא מכילה נתונים תקינים לסוג פעולה מסוים, היא מחזירה null או 0, בהתאם לסוג התוצאה שלה.

צללית גרירה

במהלך פעולת גרירה ושחרור, המערכת מציגה תמונה שהמשתמש גורר. בתמונה הזו, שמייצגת העברת נתונים, רואים את הנתונים שנגררים. בפעולות אחרות, התמונה מייצגת היבט מסוים של פעולת הגרירה.

התמונה נקראת צללית גרירה. יוצרים אותו באמצעות methods שמצהירים עליהם באובייקט View.DragShadowBuilder. מעבירים את הכלי למערכת כשמתחילים פעולת גרירה ושחרור באמצעות startDragAndDrop(). כחלק מהתגובה ל-startDragAndDrop(), המערכת מפעילה את שיטות הקריאה החוזרת שהגדרתם ב-View.DragShadowBuilder כדי לקבל צללית של הגרירה.

למחלקת View.DragShadowBuilder יש שני בנאים:

View.DragShadowBuilder(View)

הבונה הזה מקבל כל אחד מהאובייקטים של View באפליקציה. ה-constructor מאחסן את האובייקט View באובייקט View.DragShadowBuilder, כך שפונקציות ה-callback יכולות לגשת אליו כדי ליצור את צללית הגרירה. התצוגה לא חייבת להיות View שהמשתמש בוחר כדי להתחיל את פעולת הגרירה.

אם משתמשים בבונה הזה, לא צריך להרחיב את View.DragShadowBuilder או לבטל את השיטות שלו. כברירת מחדל, מקבלים צל גרירה שנראה כמו View שמועבר כארגומנט, והוא ממוקם במרכז מתחת למיקום שבו המשתמש נוגע במסך.

View.DragShadowBuilder()

אם משתמשים ב-constructor הזה, אין אובייקט View זמין באובייקט View.DragShadowBuilder. השדה מוגדר ל-null. צריך להרחיב את View.DragShadowBuilder ולשנות את ה-methods שלו, אחרת מתקבל צל גרירה בלתי נראה. המערכת לא מציגה שגיאה.

במחלקת View.DragShadowBuilder יש שתי שיטות שיוצרות יחד את הצללית של הגרירה:

onProvideShadowMetrics()

המערכת קוראת ל-method הזה מיד אחרי שקוראים ל-startDragAndDrop(). משתמשים בשיטה כדי לשלוח את המימדים ואת נקודת המגע של הצללית הגרורה למערכת. ל-method יש שני פרמטרים:

outShadowSize: אובייקט Point הרוחב של צללית הגרירה מופיע ב-x, והגובה שלה מופיע ב-y.

outShadowTouchPoint: אובייקט Point. נקודת המגע היא המיקום בתוך צללית הגרירה שצריך להיות מתחת לאצבע של המשתמש במהלך הגרירה. המיקום X שלו מופיע ב-x והמיקום Y שלו מופיע ב-y.

onDrawShadow()

מיד אחרי הקריאה ל-onProvideShadowMetrics() המערכת קוראת ל-onDrawShadow() כדי ליצור את צללית הגרירה. ל-method יש ארגומנט יחיד, אובייקט Canvas שהמערכת בונה מהפרמטרים שאתם מספקים ב-onProvideShadowMetrics(). השיטה מציירת את צללית הגרירה ב-Canvas שסופק.

כדי לשפר את הביצועים, כדאי לשמור על גודל קטן של צללית גרירה. אם מדובר בפריט אחד, כדאי להשתמש בסמל. אם בוחרים כמה פריטים, כדאי להשתמש בסמלים בערימה ולא בתמונות מלאות שמוצגות על המסך.

פונקציות event listener ושיטות callback של גרירה

View מקבלת אירועי גרירה באמצעות פונקציית event listener לגרירה שמטמיעה את View.OnDragListener או באמצעות שיטת הקריאה החוזרת onDragEvent() של התצוגה. כשהמערכת קוראת לשיטה או למאזין, היא מספקת ארגומנט DragEvent.

ברוב המקרים, עדיף להשתמש ב-listener מאשר בשיטת הקריאה החוזרת. כשמעצבים ממשקי משתמש, בדרך כלל לא יוצרים מחלקות משנה של מחלקות View, אבל השימוש בשיטת הקריאה החוזרת מחייב אתכם ליצור מחלקות משנה כדי לבטל את השיטה. לעומת זאת, אפשר להטמיע מחלקה אחת של מאזין ואז להשתמש בה עם כמה אובייקטים שונים של View. אפשר גם להטמיע אותו כמחלקה מוטמעת אנונימית או כביטוי למבדה. כדי להגדיר את מאזין לאובייקט View, קוראים ל-setOnDragListener().

אפשר גם לשנות את הטמעת ברירת המחדל של onDragEvent() בלי לבטל את השיטה. הגדרת OnReceiveContentListener בתצוגה. פרטים נוספים זמינים במאמר setOnReceiveContentListener(). השיטה onDragEvent() מבצעת את הפעולות הבאות כברירת מחדל:

  • מחזירה את הערך true בתגובה לקריאה אל startDragAndDrop().
  • שיחות performReceiveContent() אם גוררים את הנתונים ומשחררים אותם בתצוגה. הנתונים מועברים לשיטה כאובייקט ContentInfo. השיטה מפעילה את OnReceiveContentListener.

  • הפונקציה מחזירה את הערך true אם נתוני הגרירה והשחרור משוחררים בתצוגה ורכיב OnReceiveContentListener צורך חלק מהתוכן.

מגדירים את OnReceiveContentListener כדי לטפל בנתונים באופן ספציפי לאפליקציה. כדי להבטיח תאימות לאחור עד לרמת API 24, משתמשים בגרסת Jetpack של OnReceiveContentListener.

אפשר להגדיר פונקציית drag event listener ושיטת קריאה חוזרת לאובייקט View. במקרה כזה, המערכת קודם קוראת לפונקציית ה-listener. המערכת לא קוראת לשיטת הקריאה החוזרת אלא אם המאזין מחזיר false.

השילוב של השיטה onDragEvent() ושל View.OnDragListener דומה לשילוב של onTouchEvent() ושל View.OnTouchListener שמשמשים לאירועי מגע.