תפריטים הם רכיב נפוץ בממשק המשתמש של סוגים רבים של אפליקציות. כדי לספק חוויית משתמש מוכרת ועקבית, כדאי להשתמש בממשקי ה-API של Menu
כדי להציג פעולות של משתמשים ואפשרויות אחרות בפעילויות.
במסמך הזה מוסבר איך ליצור את שלושת הסוגים הבסיסיים של תפריטים או מצגות פעולה בכל הגרסאות של Android:
- תפריט האפשרויות וסרגל האפליקציות
- תפריט האפשרויות הוא האוסף הראשי של הפריטים בתפריט של פעילות. כאן ממוקמות פעולות שיש להן השפעה גלובלית על האפליקציה, כמו 'חיפוש', 'כתיבת אימייל' ו'הגדרות'.
אפשר לעיין בקטע יצירת תפריט אפשרויות.
- תפריט הקשר ומצב פעולה לפי הקשר
- תפריט הקשר הוא תפריט צף שמופיע כשהמשתמש מבצע לחיצה ארוכה על אלמנט כלשהו. הוא מספק פעולות שמשפיעות על התוכן או על מסגרת ההקשר שנבחרו.
במצב פעולה לפי הקשר מוצגים פריטים של פעולות שמשפיעות על התוכן שנבחר בסרגל בחלק העליון של המסך, ומאפשרים למשתמש לבחור כמה פריטים.
אפשר לעיין בקטע יצירת תפריט הקשר.
- תפריט קופץ
- בתפריט קופץ מוצגת רשימה אנכית של פריטים שמקובעת לתצוגה שמפעילה את התפריט. אפשר להשתמש בה כדי להציג פעולות נוספות שקשורות לתוכן ספציפי, או כדי לספק אפשרויות לחלק השני של הפקודה. הפעולות בתפריט הקופץ לא משפיעות ישירות על התוכן התואם – לזה מיועדות הפעולות לפי הקשר. במקום זאת, תפריט הקופץ מיועד לפעולות מורחבות שקשורות לאזורי תוכן בפעילות שלכם.
אפשר לעיין בקטע יצירת תפריט קופץ.
הגדרת תפריט ב-XML
לכל סוגי התפריטים, Android מספק פורמט XML סטנדרטי להגדרת פריטי התפריט. במקום ליצור תפריט בקוד של הפעילות, מגדירים תפריט וכל הפריטים שלו במשאב תפריט בפורמט XML. לאחר מכן תוכלו להנפיח את משאב התפריט – לטעון אותו כאובייקט Menu
– בפעילות או בחלק.
מומלץ להשתמש במשאב תפריט מהסיבות הבאות:
- קל יותר להציג את מבנה התפריט ב-XML באופן חזותי.
- הוא מפריד את התוכן של התפריט מהקוד ההתנהגותי של האפליקציה.
- בעזרת המסגרת של משאבי האפליקציה, אפשר ליצור הגדרות תפריט חלופיות לגרסאות שונות של פלטפורמות, לגדלים שונים של מסכים ולתצורות אחרות.
כדי להגדיר תפריט, יוצרים קובץ XML בתיקייה res/menu/
של הפרויקט ובונים את התפריט באמצעות הרכיבים הבאים:
<menu>
- מגדיר
Menu
, שהוא מאגר של פריטי תפריט. רכיב<menu>
חייב להיות צומת הבסיס של הקובץ, והוא יכול להכיל רכיב<item>
ורכיב<group>
אחד או יותר. <item>
- יוצרת
MenuItem
שמייצג פריט יחיד בתפריט. הרכיב הזה יכול להכיל רכיב<menu>
בתצוגת עץ כדי ליצור תפריט משנה. <group>
- קונטיינר אופציונלי ובלתי נראה לרכיבי
<item>
. כך אפשר לסווג את הפריטים בתפריט כך שישתפו מאפיינים, כמו מצב פעיל וגלוי. מידע נוסף זמין בקטע יצירת קבוצת תפריטים.
דוגמה לתפריט בשם game_menu.xml
:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/new_game" android:icon="@drawable/ic_new_game" android:title="@string/new_game" app:showAsAction="ifRoom"/> <item android:id="@+id/help" android:icon="@drawable/ic_help" android:title="@string/help" /> </menu>
הרכיב <item>
תומך בכמה מאפיינים שאפשר להשתמש בהם כדי להגדיר את המראה וההתנהגות של פריט. הפריטים בתפריט הקודם כוללים את המאפיינים הבאים:
android:id
- מזהה משאב ייחודי לפריט, שמאפשר לאפליקציה לזהות את הפריט כשהמשתמש בוחר בו.
android:icon
- הפניה ל-drawable שישמש כסמל של הפריט.
android:title
- הפניה למחרוזת שתשמש בתור שם הפריט.
android:showAsAction
- המפרט של המועד והאופן שבו הפריט הזה יופיע כפריט פעולה בסרגל האפליקציות.
אלה המאפיינים החשובים ביותר שבהם אתם משתמשים, אבל יש עוד הרבה מאפיינים זמינים. מידע על כל המאפיינים הנתמכים זמין במסמכי העזרה בנושא משאב תפריט.
כדי להוסיף תפריט משנה לפריט בתפריט כלשהו, מוסיפים רכיב <menu>
כצאצא של <item>
.
תפריטי משנה שימושיים כשיש באפליקציה הרבה פונקציות שאפשר לארגן לפי נושאים, כמו פריטים בסרגל התפריטים של אפליקציה במחשב – למשל קובץ, עריכה ותצוגה. דוגמה:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/file" android:title="@string/file" > <!-- "file" submenu --> <menu> <item android:id="@+id/create_new" android:title="@string/create_new" /> <item android:id="@+id/open" android:title="@string/open" /> </menu> </item> </menu>
כדי להשתמש בתפריט בפעילות, צריך _להנפיח_ את משאב התפריט, ולהמיר את משאב ה-XML לאובייקט שניתן לתכנות באמצעות MenuInflater.inflate()
.
בקטעים הבאים מוסבר איך להרחיב תפריט לכל סוג תפריט.
יצירת תפריט אפשרויות
בתפריט האפשרויות, כמו זה שמוצג באיור 1, אפשר לכלול פעולות ואפשרויות אחרות שרלוונטיות להקשר של הפעילות הנוכחית, כמו 'חיפוש', 'כתיבת אימייל' ו'הגדרות'.
![תמונה שבה מוצגת שורת האפליקציות של אפליקציית Google Sheets](https://developer.android.google.cn/static/images/training/appbar/appbar_sheets_2x.png?authuser=7&hl=he)
אפשר להצהיר על פריטים לתפריט האפשרויות ממעמד המשנה Activity
או ממעמד המשנה Fragment
. אם גם הפעילות וגם הפאזות מגדירים פריטים לתפריט האפשרויות, הפריטים משולבים בממשק המשתמש. הפריטים של הפעילות מופיעים קודם, ואחריהם הפריטים של כל קטע, לפי הסדר שבו הקטעים נוספים לפעילות. אם צריך, אפשר לשנות את הסדר של פריטי התפריט באמצעות המאפיין android:orderInCategory
בכל <item>
שרוצים להעביר.
כדי לציין את תפריט האפשרויות של פעילות, משנים את הערך של onCreateOptionsMenu()
.
לקטעים יש קריאה חוזרת (callback) משלהם של onCreateOptionsMenu()
. בשיטה הזו אפשר לנפח את משאב התפריט, הוגדר ב-XML, ל-Menu
שסופק ב-callback. הדוגמה הבאה ממחישה זאת:
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater: MenuInflater = menuInflater inflater.inflate(R.menu.game_menu, menu) return true }
Java
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; }
אפשר גם להוסיף אפשרויות לתפריט באמצעות add()
ולשלוף פריטים באמצעות findItem()
כדי לשנות את המאפיינים שלהם באמצעות ממשקי ה-API של MenuItem
.
טיפול באירועי קליקים
כשהמשתמש בוחר פריט מתפריט האפשרויות, כולל פריטים של פעולות בסרגל האפליקציות, המערכת קוראת לשיטה onOptionsItemSelected()
של הפעילות. השיטה הזו מעבירה את MenuItem
שנבחר. אפשר לזהות את הפריט באמצעות קריאה ל-getItemId()
, שמחזירה את המזהה הייחודי של פריט התפריט, שמוגדר על ידי המאפיין android:id
במשאב התפריט או באמצעות מספר שלם שסופק לשיטה add()
. אפשר להתאים את המזהה הזה לפריטי תפריט ידועים כדי לבצע את הפעולה המתאימה.
Kotlin
override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle item selection. return when (item.itemId) { R.id.new_game -> { newGame() true } R.id.help -> { showHelp() true } else -> super.onOptionsItemSelected(item) } }
Java
@Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection. switch (item.getItemId()) { case R.id.new_game: newGame(); return true; case R.id.help: showHelp(); return true; default: return super.onOptionsItemSelected(item); } }
כשמסיימים לטפל בפריט בתפריט, מחזירים את הערך true
. אם לא מטפלים בפריט התפריט, צריך להפעיל את ההטמעה של onOptionsItemSelected()
מהסופר-קלאס. ההטמעה שמוגדרת כברירת מחדל מחזירה את הערך false.
אם הפעילות כוללת קטעים, המערכת קודם קוראת ל-onOptionsItemSelected()
עבור הפעילות, ואז לכל קטע בסדר שבו הקטעים נוספו, עד שאחד מהם מחזיר את הערך true
או שכל הקטעים נקראים.
שינוי של אפשרויות בתפריט בזמן ריצה
אחרי שהמערכת קוראת ל-onCreateOptionsMenu()
, היא שומרת מופע של Menu
שאתם מאכלסים ולא קוראת שוב ל-onCreateOptionsMenu()
, אלא אם התפריט לא תקף.
עם זאת, צריך להשתמש ב-onCreateOptionsMenu()
רק כדי ליצור את מצב התפריט הראשוני, ולא כדי לבצע שינויים במהלך מחזור החיים של הפעילות.
אם רוצים לשנות את תפריט האפשרויות על סמך אירועים שמתרחשים במהלך מחזור החיים של הפעילות, אפשר לעשות זאת בשיטה onPrepareOptionsMenu()
. השיטה הזו מעבירה את האובייקט Menu
כפי שהוא קיים כרגע, כדי שתוכלו לשנות אותו, למשל על ידי הוספה, הסרה או השבתה של פריטים.
בנוסף, קטעי קוד מספקים קריאה חוזרת (callback) מסוג onPrepareOptionsMenu()
.
תפריט האפשרויות נחשב תמיד פתוח כשפריטי התפריט מוצגים בסרגל האפליקציות. כשאירוע מתרחש ואתם רוצים לבצע עדכון של התפריט, צריך לבצע קריאה ל-invalidateOptionsMenu()
כדי לבקש מהמערכת לבצע קריאה ל-onPrepareOptionsMenu()
.
יצירת תפריט הקשר
![תמונה שבה מוצג תפריט הקשר צף](https://developer.android.google.cn/static/develop/ui/views/images/context_menu_no_icons.png?authuser=7&hl=he)
תפריט הקשר מציע פעולות שמשפיעות על פריט ספציפי או על מסגרת הקשר ספציפית בממשק המשתמש. אפשר לספק תפריט הקשר לכל תצוגה, אבל בדרך כלל משתמשים בו לפריטים ב-RecylerView
או באוספים אחרים של תצוגות שבהם המשתמש יכול לבצע פעולות ישירות על כל פריט.
יש שתי דרכים לספק פעולות לפי הקשר:
- בתפריט הקשר צף. תפריט מופיע כרשימה צפה של פריטי תפריט, בדומה לתיבת דו-שיח, כשהמשתמש מבצע לחיצה ארוכה על תצוגה שמצהירה על תמיכה בתפריט הקשר. משתמשים יכולים לבצע פעולה לפי הקשר בפריט אחד בכל פעם.
- במצב פעולה לפי הקשר. המצב הזה הוא הטמעה מערכתית של
ActionMode
שמציגה בחלק העליון של המסך סרגל פעולות לפי הֶקשר(CAB) עם פריטים של פעולות שמשפיעות על הפריטים שנבחרו. כשהמצב הזה פעיל, המשתמשים יכולים לבצע פעולה על כמה פריטים בו-זמנית, אם האפליקציה תומכת בכך.
הערה: בתפריט ההקשר אין תמיכה במקשי קיצור לפריטים ובסמלי פריטים.
יצירת תפריט הקשר צף
כדי להציג תפריט הקשר צף:
- כדי לרשום את ה-
View
שאליו משויך תפריט ההקשר, צריך להפעיל אתregisterForContextMenu()
ולהעביר לו את ה-View
.אם בפעילות שלכם נעשה שימוש ב-
RecyclerView
ואתם רוצים שכל הפריטים יציעו את אותו תפריט הקשר, צריך לרשום את כל הפריטים לתפריט הקשר על ידי העברת ה-RecyclerView
אלregisterForContextMenu()
. - מטמיעים את השיטה
onCreateContextMenu()
ב-Activity
או ב-Fragment
.כשבתצוגה הרשומה מתקבל אירוע של לחיצה ארוכה, המערכת קולטת את האירוע ומפעילה את השיטה
onCreateContextMenu()
. כאן מגדירים את הפריטים בתפריט, בדרך כלל על ידי ניפוח של משאב תפריט, כמו בדוגמה הבאה:Kotlin
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo) { super.onCreateContextMenu(menu, v, menuInfo) val inflater: MenuInflater = menuInflater inflater.inflate(R.menu.context_menu, menu) }
Java
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); }
MenuInflater
מאפשרת להרחיב את תפריט ההקשר ממשאב תפריט. הפרמטרים של שיטת ה-callback כוללים אתView
שהמשתמש בוחר ואובייקטContextMenu.ContextMenuInfo
שמספק מידע נוסף על הפריט שנבחר. אם לפעילות יש כמה תצוגות, שכל אחת מהן מספקת תפריט הקשר שונה, תוכלו להשתמש בפרמטרים האלה כדי לקבוע איזה תפריט הקשר תנפחו. מטמיעים את
onContextItemSelected()
, כפי שמוצג בדוגמה הבאה. כשהמשתמש בוחר פריט תפריט, המערכת קורא ל-method הזה כדי שתוכלו לבצע את הפעולה המתאימה.Kotlin
override fun onContextItemSelected(item: MenuItem): Boolean { val info = item.menuInfo as AdapterView.AdapterContextMenuInfo return when (item.itemId) { R.id.edit -> { editNote(info.id) true } R.id.delete -> { deleteNote(info.id) true } else -> super.onContextItemSelected(item) } }
Java
@Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.edit: editNote(info.id); return true; case R.id.delete: deleteNote(info.id); return true; default: return super.onContextItemSelected(item); } }
השיטה
getItemId()
שולחת שאילתה לגבי המזהה של פריט התפריט שנבחר, ומקצה את המזהה הזה לכל פריט תפריט ב-XML באמצעות המאפייןandroid:id
, כפי שמתואר בקטע הגדרת תפריט ב-XML.כשמסיימים לטפל בפריט בתפריט, מחזירים את הערך
true
. אם לא מטפלים בפריט התפריט, מעבירים אותו להטמעה של הכיתה האב. אם הפעילות כוללת קטעים, הקריאה החוזרת הזו תישלח אליה קודם. כשקוראים לסופר-קלאס במקרה של אירוע שלא טופל, המערכת מעבירה את האירוע לשיטת ה-callback המתאימה בכל קטע, אחד אחרי השני, לפי הסדר שבו כל קטע נוסף, עד שהיא מחזירה את הערךtrue
אוfalse
. הטמעות ברירת המחדל שלActivity
ו-android.app.Fragment
מחזירות את הערךfalse
, לכן תמיד צריך לקרוא לסופר-קלאס כשהאירוע לא מטופל.
שימוש במצב פעולה לפי הקשר
מצב הפעולות לפי הקשר הוא הטמעה מערכתית של ActionMode
שמתמקדת באינטראקציה של המשתמשים לביצוע פעולות לפי הקשר. כשמשתמש מפעיל את המצב הזה על ידי בחירה בפריט, סרגל הפעולות לפי הקשר מופיע בחלק העליון של המסך כדי להציג את הפעולות שהמשתמש יכול לבצע בפריטים שנבחרו. כשהמצב הזה מופעל, המשתמש יכול לבחור כמה פריטים, אם האפליקציה תומכת בכך, ולבטל את הבחירה בפריטים ולהמשיך לנווט בפעילות. מצב הפעולה מושבת וסרגל הפעולות לפי הקשר נעלם כשהמשתמש מבטל את הבחירה בכל הפריטים, מקייש על הלחצן 'הקודם' או מקייש על הפעולה סיום בצד ימין של הסרגל.
בתצוגות שמציעות פעולות לפי הקשר, בדרך כלל מפעילים את מצב הפעולה לפי הקשר כשמתרחש אחד משני האירועים הבאים:
- המשתמש מבצע לחיצה ארוכה על התצוגה.
- המשתמש בוחר תיבת סימון או רכיב דומה בממשק המשתמש בתצוגה.
האופן שבו האפליקציה מפעילה את מצב הפעולה לפי הקשר ומגדירה את ההתנהגות של כל פעולה תלוי בעיצוב שלכם. יש שני עיצובים:
- לפעולות לפי הקשר בתצוגות ספציפיות שרירותיות.
- כדי לבצע פעולות לפי הקשר בכמות גדולה על קבוצות של פריטים ב-
RecyclerView
, ומאפשרות למשתמש לבחור כמה פריטים ולבצע פעולה על כולם.
בקטעים הבאים מתוארת ההגדרה הנדרשת לתרחיש הראשון.
הפעלת מצב פעולה לפי הקשר בתצוגות ספציפיות
אם רוצים להפעיל את מצב הפעולה לפי הקשר רק כשהמשתמש בוחר תצוגות ספציפיות, צריך לבצע את הפעולות הבאות:
- מטמיעים את הממשק
ActionMode.Callback
כפי שמוצג בדוגמה הבאה. בשיטות החזרה (callbacks) שלו, אפשר לציין את הפעולות של שורת הפעולות לפי הקשר, להגיב לאירועי לחיצה על פריטי פעולה ולטפל באירועים אחרים במחזור החיים של מצב הפעולה.Kotlin
private val actionModeCallback = object : ActionMode.Callback { // Called when the action mode is created. startActionMode() is called. override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { // Inflate a menu resource providing context menu items. val inflater: MenuInflater = mode.menuInflater inflater.inflate(R.menu.context_menu, menu) return true } // Called each time the action mode is shown. Always called after // onCreateActionMode, and might be called multiple times if the mode // is invalidated. override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { return false // Return false if nothing is done } // Called when the user selects a contextual menu item. override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { return when (item.itemId) { R.id.menu_share -> { shareCurrentItem() mode.finish() // Action picked, so close the CAB. true } else -> false } } // Called when the user exits the action mode. override fun onDestroyActionMode(mode: ActionMode) { actionMode = null } }
Java
private ActionMode.Callback actionModeCallback = new ActionMode.Callback() { // Called when the action mode is created. startActionMode() is called. @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate a menu resource providing context menu items. MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); return true; } // Called each time the action mode is shown. Always called after // onCreateActionMode, and might be called multiple times if the mode // is invalidated. @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; // Return false if nothing is done. } // Called when the user selects a contextual menu item. @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.menu_share: shareCurrentItem(); mode.finish(); // Action picked, so close the CAB. return true; default: return false; } } // Called when the user exits the action mode. @Override public void onDestroyActionMode(ActionMode mode) { actionMode = null; } };
פונקציות ה-callbacks של האירועים האלה כמעט זהות לפונקציות ה-callbacks של תפריט האפשרויות, מלבד העובדה שכל אחת מהן מעבירה גם את האובייקט
ActionMode
שמשויך לאירוע. אפשר להשתמש בממשקי ה-API שלActionMode
כדי לבצע שינויים שונים ב-CAB, למשל לשנות את הכותרת ואת הכותרת המשנית באמצעותsetTitle()
ו-setSubtitle()
, כדי לציין כמה פריטים נבחרו.בדוגמה הקודמת, משתנה
actionMode
מוגדר ל-null
כשמצב הפעולה נהרס. בשלב הבא נסביר איך מפעילים את המשתנה ואיך אפשר לשמור את משתנה המשתמש בפעילות או בקטע. - צריך להפעיל את
startActionMode()
כשרוצים להציג את הסרגל, למשל כשהמשתמש מבצע לחיצה ארוכה על התצוגה.Kotlin
someView.setOnLongClickListener { view -> // Called when the user performs a touch & hold on someView. when (actionMode) { null -> { // Start the CAB using the ActionMode.Callback defined earlier. actionMode = activity?.startActionMode(actionModeCallback) view.isSelected = true true } else -> false } }
Java
someView.setOnLongClickListener(new View.OnLongClickListener() { // Called when the user performs a touch & hold on someView. public boolean onLongClick(View view) { if (actionMode != null) { return false; } // Start the CAB using the ActionMode.Callback defined earlier. actionMode = getActivity().startActionMode(actionModeCallback); view.setSelected(true); return true; } });
כשקוראים לפונקציה
startActionMode()
, המערכת מחזירה את הערך שלActionMode
שנוצר. שמירת המידע במשתנה חבר מאפשרת לבצע שינויים בסרגל הפעולות לפי הקשר בתגובה לאירועים אחרים. בדוגמה הקודמת, המשתנהActionMode
משמש כדי לוודא שהמכונה שלActionMode
לא נוצרת מחדש אם היא כבר פעילה, על ידי בדיקה אם המשתנה הוא null לפני שמתחילים את מצב הפעולה.
יצירת תפריט קופץ
![תמונה שמציגה תפריט קופץ באפליקציית Gmail, שמקובע לכפתור האפשרויות הנוספות בפינה השמאלית העליונה.](https://developer.android.google.cn/static/images/ui/popupmenu.png?authuser=7&hl=he)
PopupMenu
הוא תפריט מודלי שמקובע ל-View
. הוא מופיע מתחת לתצוגת הצ'אט הראשית אם יש מקום, או מעל לתצוגה אחרת. האפשרות הזו שימושית במקרים הבאים:
- הצגת תפריט בסגנון 'overflow' לפעולות שקשורות לתוכן ספציפי, כמו כותרות האימייל ב-Gmail, כפי שמוצג באיור 4.
- מתן חלק שני של משפט פקודה, למשל לחצן עם הכיתוב Add (הוספה) שפותח תפריט קופץ עם אפשרויות שונות של Add (הוספה).
- הצגת תפריט דומה ל-
Spinner
שלא שומר בחירה קבועה.
אם מגדירים את התפריט ב-XML, כך מציגים את התפריט הקופץ:
- יוצרים מופע של
PopupMenu
באמצעות ה-constructor שלו, שמקבל את האפליקציה הנוכחיתContext
ואתView
שאליו התפריט מוצמדות. - משתמשים ב-
MenuInflater
כדי לנפח את משאב התפריט לאובייקטMenu
שמוחזר על ידיPopupMenu.getMenu()
. - התקשרות אל
PopupMenu.show()
.
לדוגמה, הנה לחצן שמוצג בו תפריט קופץ:
<ImageButton android:id="@+id/dropdown_menu" android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@string/descr_overflow_button" android:src="@drawable/arrow_drop_down" />
לאחר מכן, התפריט הקופץ יוצג בפעילות כך:
Kotlin
findViewById<ImageButton>(R.id.dropdown_menu).setOnClickListener { val popup = PopupMenu(this, it) val inflater: MenuInflater = popup.menuInflater inflater.inflate(R.menu.actions, popup.menu) popup.show() }
Java
findViewById(R.id.dropdown_menu).setOnClickListener(v -> { PopupMenu popup = new PopupMenu(this, v); popup.getMenuInflater().inflate(R.menu.actions, popup.getMenu()); popup.show(); });
התפריט נסגר כשהמשתמש בוחר פריט או מקייש מחוץ לאזור התפריט. אפשר להאזין לאירוע הדחייה באמצעות PopupMenu.OnDismissListener
.
טיפול באירועי קליקים
כדי לבצע פעולה כשהמשתמש בוחר פריט בתפריט, מטמיעים את הממשק PopupMenu.OnMenuItemClickListener
ומירשם אותו ב-PopupMenu
באמצעות קריאה ל-setOnMenuItemclickListener()
.
כשהמשתמש בוחר פריט, המערכת קוראת ל-callback onMenuItemClick()
בממשק.
הדוגמה הבאה ממחישה זאת:
Kotlin
fun showMenu(v: View) { PopupMenu(this, v).apply { // MainActivity implements OnMenuItemClickListener. setOnMenuItemClickListener(this@MainActivity) inflate(R.menu.actions) show() } } override fun onMenuItemClick(item: MenuItem): Boolean { return when (item.itemId) { R.id.archive -> { archive(item) true } R.id.delete -> { delete(item) true } else -> false } }
Java
public void showMenu(View v) { PopupMenu popup = new PopupMenu(this, v); // This activity implements OnMenuItemClickListener. popup.setOnMenuItemClickListener(this); popup.inflate(R.menu.actions); popup.show(); } @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.archive: archive(item); return true; case R.id.delete: delete(item); return true; default: return false; } }
יצירת קבוצת תפריטים
קבוצת תפריטים היא אוסף של פריטי תפריט שיש להם מאפיינים משותפים. בעזרת קבוצה תוכלו:
- מציגים או מסתירים את כל הפריטים באמצעות
setGroupVisible()
. - מפעילים או משביתים את כל הפריטים באמצעות
setGroupEnabled()
. - מציינים אם אפשר לסמן את כל הפריטים באמצעות
setGroupCheckable()
.
אפשר ליצור קבוצה על ידי הטמעת רכיבי <item>
בתוך רכיב <group>
במשאב התפריט, או על ידי ציון מזהה קבוצה באמצעות השיטה add()
.
דוגמה למשאב תפריט שכולל קבוצה:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_save" android:icon="@drawable/menu_save" android:title="@string/menu_save" /> <!-- menu group --> <group android:id="@+id/group_delete"> <item android:id="@+id/menu_archive" android:title="@string/menu_archive" /> <item android:id="@+id/menu_delete" android:title="@string/menu_delete" /> </group> </menu>
הפריטים בקבוצה מופיעים באותו הרמה כמו הפריט הראשון – כל שלושת הפריטים בתפריט הם אחים. עם זאת, אפשר לשנות את המאפיינים של שני הפריטים בקבוצה על ידי הפניה למזהה הקבוצה ושימוש בשיטות הקודמות. בנוסף, המערכת לעולם לא מפרידה בין פריטים מקובצים. לדוגמה, אם מגדירים את android:showAsAction="ifRoom"
לכל פריט, שניהם מופיעים בסרגל הפעולות או שניהם מופיעים בסרגל האפשרויות הנוספות של הפעולות.
שימוש באפשרויות בתפריט שניתן לסמן
תפריט יכול לשמש כממשק להפעלה או להשבתה של אפשרויות, באמצעות תיבת סימון לאפשרויות עצמאיות או לחצני בחירה לקבוצות של אפשרויות בלעדיות. באיור 5 מוצג תפריט משנה עם פריטים שאפשר לסמן באמצעות לחצני בחירה.
אפשר להגדיר את ההתנהגות של האפשרויות לבחירה בפריטי תפריט ספציפיים באמצעות המאפיין android:checkable
ברכיב <item>
, או בקבוצה שלמה באמצעות המאפיין android:checkableBehavior
ברכיב <group>
. לדוגמה, אפשר לסמן את כל הפריטים בקבוצת התפריט הזו באמצעות לחצן בחירה:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/red" android:title="@string/red" /> <item android:id="@+id/blue" android:title="@string/blue" /> </group> </menu>
המאפיין android:checkableBehavior
מקבל אחד מהערכים הבאים:
single
- אפשר לסמן רק פריט אחד מהקבוצה, וכתוצאה מכך יופיעו לחצני רדיו.
all
- אפשר לסמן את כל הפריטים, וכתוצאה מכך יופיעו תיבות סימון.
none
- לא ניתן לסמן פריטים.
אפשר להחיל מצב מסומן כברירת מחדל על פריט באמצעות המאפיין android:checked
ברכיב <item>
, ולשנות אותו בקוד באמצעות השיטה setChecked()
.
כשבוחרים פריט שאפשר לסמן, המערכת קוראת לשיטת ה-callback הרלוונטית של הפריט שנבחר, למשל onOptionsItemSelected()
.
כאן מגדירים את המצב של תיבת הסימון, כי תיבת סימון או לחצן בחירת אפשרות לא משנים את המצב שלהם באופן אוטומטי. אפשר לשלוח שאילתה לגבי המצב הנוכחי של הפריט – כפי שהיה לפני שהמשתמש בחר בו – באמצעות isChecked()
, ואז להגדיר את המצב המסומן באמצעות setChecked()
. הדוגמה הבאה ממחישה זאת:
Kotlin
override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.vibrate, R.id.dont_vibrate -> { item.isChecked = !item.isChecked true } else -> super.onOptionsItemSelected(item) } }
Java
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.vibrate: case R.id.dont_vibrate: if (item.isChecked()) item.setChecked(false); else item.setChecked(true); return true; default: return super.onOptionsItemSelected(item); } }
אם לא מגדירים את המצב המסומן כך, המצב הגלוי של תיבת הסימון או לחצן הבחירה לא ישתנה כשהמשתמש יבחר בהם. כשמגדירים את המצב, הפעילות שומרת את המצב המסומן של הפריט, כך שכשהמשתמש יפתח את התפריט מאוחר יותר, המצב המסומן שהגדרתם יהיה גלוי.
הוספת פריטים לתפריט על סמך כוונת השימוש
לפעמים רוצים שפריט תפריט יופעל פעילות באמצעות Intent
, בין אם מדובר בפעילות באפליקציה ובין אם באפליקציה אחרת. אם אתם יודעים את הכוונה שבה אתם רוצים להשתמש ויש לכם פריט תפריט ספציפי שמפעיל את הכוונה, תוכלו להפעיל את הכוונה באמצעות startActivity()
במהלך שיטת ה-callback המתאימה לבחירת פריט, כמו ה-callback onOptionsItemSelected()
.
עם זאת, אם אתם לא בטוחים שהמכשיר של המשתמש מכיל אפליקציה שמטפלת בכוונה, הוספת פריט תפריט שמפעיל אותה עלולה לגרום לכך שפריט התפריט לא יפעל, כי ייתכן שהכוונה לא תיפתר לפעילות. כדי לפתור את הבעיה, מערכת Android מאפשרת להוסיף פריטים לתפריט באופן דינמי כשהיא מאתרת במכשיר פעילויות שמטפלות בכוונה שלכם.
כדי להוסיף אפשרויות לתפריט על סמך פעילויות זמינות שמקבלות כוונה, מבצעים את הפעולות הבאות:
- מגדירים כוונה עם הקטגוריה
CATEGORY_ALTERNATIVE
אוCATEGORY_SELECTED_ALTERNATIVE
, או עם שתיהן, וגם עם כל דרישות אחרות. - מתקשרים למספר
Menu.addIntentOptions()
. לאחר מכן, Android מחפשת אפליקציות שיכולות לבצע את הכוונה ומוסיפה אותן לתפריט.
אם אין אפליקציות מותקנות שעומדות בכוונה, לא מתווספים פריטים לתפריט.
הדוגמה הבאה ממחישה זאת:
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) // Create an Intent that describes the requirements to fulfill, to be // included in the menu. The offering app must include a category value // of Intent.CATEGORY_ALTERNATIVE. val intent = Intent(null, dataUri).apply { addCategory(Intent.CATEGORY_ALTERNATIVE) } // Search and populate the menu with acceptable offering apps. menu.addIntentOptions( R.id.intent_group, // Menu group to which new items are added. 0, // Unique item ID (none). 0, // Order for the items (none). this.componentName, // The current activity name. null, // Specific items to place first (none). intent, // Intent created above that describes the requirements. 0, // Additional flags to control items (none). null) // Array of MenuItems that correlate to specific items (none). return true }
Java
@Override public boolean onCreateOptionsMenu(Menu menu){ super.onCreateOptionsMenu(menu); // Create an Intent that describes the requirements to fulfill, to be // included in the menu. The offering app must include a category value // of Intent.CATEGORY_ALTERNATIVE. Intent intent = new Intent(null, dataUri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); // Search and populate the menu with acceptable offering apps. menu.addIntentOptions( R.id.intent_group, // Menu group to which new items are added. 0, // Unique item ID (none). 0, // Order for the items (none). this.getComponentName(), // The current activity name. null, // Specific items to place first (none). intent, // Intent created above that describes the requirements. 0, // Additional flags to control items (none). null); // Array of MenuItems that correlate to specific items (none). return true; }
לכל פעילות שנמצאה שמספקת מסנן כוונה שמתאים לכוונה שהוגדרה, מתווסף פריט תפריט. הערך בשדה android:label
של מסנן הכוונה משמש בתור שם פריט התפריט, וסמל האפליקציה משמש בתור סמל פריט התפריט. השיטה addIntentOptions()
מחזירה את מספר הפריטים שנוספו לתפריט.
לאפשר הוספה של הפעילות שלכם לתפריטים אחרים
אתם יכולים להציע את השירותים של הפעילות שלכם לאפליקציות אחרות, כדי שהאפליקציה שלכם תוכל להיכלל בתפריט שלהן – ההפך מהתפקידים שתוארו למעלה.
כדי להופיע בתפריטי אפליקציות אחרים, מגדירים מסנן אינטרנט כרגיל, אבל כוללים את הערכים CATEGORY_ALTERNATIVE
או CATEGORY_SELECTED_ALTERNATIVE
, או את שניהם, בקטגוריה של מסנן האינטראקציה. הדוגמה הבאה ממחישה זאת:
<intent-filter label="@string/resize_image"> ... <category android:name="android.intent.category.ALTERNATIVE" /> <category android:name="android.intent.category.SELECTED_ALTERNATIVE" /> ... </intent-filter>
מידע נוסף על כתיבת מסנני כוונות מפורט במאמר כוונות ומסנני כוונות.