תפריטים הם רכיב נפוץ בממשק המשתמש בסוגים רבים של אפליקציות. כדי לספק חוויית משתמש מוכרת ועקבית, כדאי להשתמש בממשקי ה-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, אפשר לכלול פעולות ואפשרויות אחרות שרלוונטיות להקשר הפעילות הנוכחית, כמו 'חיפוש', 'כתיבת אימייל' ו'הגדרות'.
אפשר להצהיר על פריטים לתפריט האפשרויות מתוך מחלקת המשנה Activity
Fragment
או מתוך מחלקת משנה. אם גם הפעילות וגם המקטעים מצהירים על פריטים בתפריט האפשרויות, הפריטים משולבים בממשק המשתמש. הפריטים של הפעילות מופיעים ראשונים, ואחריהם הפריטים של כל אחד מהקטעים, לפי הסדר שבו הקטעים נוספו לפעילות. במקרה הצורך, אפשר לשנות את הסדר של הפריטים בתפריט באמצעות מאפיין android:orderInCategory בכל <item> שרוצים להעביר.
כדי לציין את תפריט האפשרויות לפעילות, מחליפים את onCreateOptionsMenu().
ל-Fragments יש קריאה חוזרת (callback) משלהם onCreateOptionsMenu(). בשיטה הזו, אפשר להרחיב את משאב התפריט, שמוגדר ב-XML, לתוך Menu שמוגדר בקריאה החוזרת. כך זה נראה בדוגמה הבאה:
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() של הפעילות. ה-method הזה מעביר את 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 כמו שהוא קיים כרגע, כדי שתוכלו לשנות אותו, למשל להוסיף, להסיר או להשבית פריטים.
בנוסף, יש ל-Fragments פונקציית קריאה חוזרת (callback) מסוג onPrepareOptionsMenu().
תפריט האפשרויות נחשב תמיד פתוח כשפריטים בתפריט מוצגים בסרגל האפליקציות. כשמתרחש אירוע ואתם רוצים לעדכן את התפריט, אתם יכולים להפעיל את invalidateOptionsMenu() כדי לבקש מהמערכת להפעיל את onPrepareOptionsMenu().
יצירת תפריט הקשר
תפריט הקשר מציע פעולות שמשפיעות על פריט ספציפי או על מסגרת הקשר בממשק המשתמש. אפשר לספק תפריט הקשר לכל תצוגה, אבל בדרך כלל משתמשים בהם לפריטים ב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(), כמו בדוגמה הבאה. כשמשתמש בוחר פריט בתפריט, המערכת קוראת לשיטה הזו כדי שתוכלו לבצע את הפעולה המתאימה.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. אם לא מטפלים בפריט התפריט, מעבירים את פריט התפריט להטמעה של מחלקת העל. אם הפעילות כוללת קטעים, הפעילות מקבלת את הקריאה החוזרת הזו קודם. כשקוראים למחלקת העל כשלא מטפלים באירוע, המערכת מעבירה את האירוע לשיטת הקריאה החוזרת המתאימה בכל קטע, בכל פעם קטע אחד, לפי הסדר שבו כל קטע נוסף, עד שמוחזרtrueאוfalse. ההטמעות שמוגדרות כברירת מחדל עבור Activityו-android.app.Fragmentמחזירות false, לכן תמיד צריך להתקשר למחלקת העל כשלא מטפלים בבקשה.
שימוש במצב פעולה לפי הקשר
מצב פעולה לפי הקשר הוא הטמעה של המערכת ActionMode שממקדת את אינטראקציית המשתמש בביצוע פעולות לפי הקשר. כשמשתמש מפעיל את המצב הזה על ידי בחירת פריט, סרגל פעולות בהקשר מופיע בחלק העליון של המסך כדי להציג פעולות שהמשתמש יכול לבצע על הפריטים שנבחרו. בזמן שהמצב הזה מופעל, המשתמש יכול לבחור כמה פריטים, אם האפליקציה תומכת בכך, ולבטל את הבחירה בפריטים ולהמשיך לנווט בפעילות. מצב הפעולה מושבת וסרגל הפעולות ההקשרי נעלם כשהמשתמש מבטל את הסימון של כל הפריטים, מקיש על לחצן החזרה או מקיש על הפעולה סיום בצד ימין של הסרגל.
בתצוגות שמספקות פעולות לפי הקשר, בדרך כלל מפעילים את מצב הפעולה לפי הקשר כשמתרחש אחד משני האירועים הבאים או שניהם:
- המשתמש מבצע לחיצה ארוכה על התצוגה.
- המשתמש בוחר תיבת סימון או רכיב דומה בממשק המשתמש בתצוגה.
האופן שבו האפליקציה מפעילה את מצב פעולה לפי הקשר ומגדירה את ההתנהגות של כל פעולה תלוי בעיצוב שלכם. יש שני עיצובים:
- לפעולות לפי הקשר בתצוגות שרירותיות של נתונים.
- לפעולות קבוצתיות בהקשר של קבוצות פריטים ב-
RecyclerView, שמאפשרות למשתמש לבחור כמה פריטים ולבצע עליהם פעולה.
בקטעים הבאים מתואר תהליך ההגדרה שנדרש לתרחיש הראשון.
הפעלת מצב פעולה לפי הקשר בתצוגות נפרדות
אם רוצים להפעיל את מצב הפעולה לפי הקשר רק כשהמשתמש בוחר תצוגות ספציפיות, צריך לבצע את הפעולות הבאות:
- מטמיעים את הממשק
ActionMode.Callbackכמו בדוגמה הבאה. בשיטות הקריאה החוזרת שלו, אפשר לציין את הפעולות עבור סרגל הפעולות ההקשרי, להגיב לאירועי לחיצה על פריטי פעולה ולטפל באירועים אחרים במחזור החיים של מצב הפעולה.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) האלה של האירועים כמעט זהות לקריאות החוזרות של תפריט האפשרויות, אלא שכל אחת מהן מעבירה גם את האובייקט
ActionModeשמשויך לאירוע. אפשר להשתמש בממשקי API שלActionModeכדי לבצע שינויים שונים ב-CAB, כמו שינוי הכותרת והכותרת המשנית באמצעותsetTitle()ו-setSubtitle(), שימושי כדי לציין כמה פריטים נבחרו.בדוגמה שלמעלה, המשתנה
actionModeמוגדר לערךnullכשמצב הפעולה מושמד. בשלב הבא, נסביר איך המשתנה מאותחל ואיך יכול להיות שימושי לשמור את משתנה החבר בפעילות או בקטע. - Call
startActionMode()when you want to show the bar, such as when the user performs a touch & hold on the view.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 לפני הפעלת מצב הפעולה.
יצירת תפריט קופץ
PopupMenu
הוא תפריט מודאלי שמעוגן לView. הוא מופיע מתחת לתצוגת העוגן אם יש מקום, או מעל התצוגה אם אין מקום. היא שימושית במקרים הבאים:
- הוספת תפריט בסגנון overflow לפעולות שקשורות לתוכן ספציפי, כמו כותרות אימייל ב-Gmail, שמוצגות באיור 4.
- לספק חלק שני של משפט פקודה, כמו לחצן עם הכיתוב הוספה שפותח תפריט קופץ עם אפשרויות שונות של הוספה.
- הצגת תפריט דומה ל-
Spinnerשלא שומר על בחירה קבועה.
אם הגדרתם את התפריט ב-XML, כך תוכלו להציג את התפריט הקופץ:
- יוצרים מופע של
PopupMenuבאמצעות בנאי, שמקבל את האפליקציה הנוכחית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(); });
התפריט נסגר כשמשתמש בוחר פריט או מקיש מחוץ לאזור התפריט. אפשר להאזין לאירוע dismiss באמצעות
PopupMenu.OnDismissListener.
טיפול באירועים מסוג קליק
כדי לבצע פעולה כשמשתמש בוחר פריט בתפריט, צריך להטמיע את
PopupMenu.OnMenuItemClickListener
הממשק ולרשום אותו ב-PopupMenu על ידי קריאה ל-setOnMenuItemclickListener().
כשהמשתמש בוחר פריט, המערכת קוראת לקריאה החוזרת 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() במהלך שיטת הקריאה החוזרת המתאימה on-item-selected, כמו הקריאה החוזרת onOptionsItemSelected().
עם זאת, אם אתם לא בטוחים שבמכשיר של המשתמש יש אפליקציה שמטפלת ב-Intent, הוספה של פריט בתפריט שמפעיל אותו עלולה לגרום לכך שהפריט לא יפעל, כי יכול להיות שה-Intent לא יפנה לפעילות. כדי לפתור את הבעיה הזו, מערכת Android מאפשרת להוסיף באופן דינמי פריטים לתפריט כשמערכת Android מוצאת פעילויות במכשיר שמטפלות ב-Intent.
כדי להוסיף אפשרויות לתפריט על סמך פעילויות זמינות שמקבלות כוונה, מבצעים את הפעולות הבאות:
- מגדירים כוונת רכישה עם הקטגוריה
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; }
לכל פעילות שנמצאה ומספקת מסנן Intent שתואם ל-Intent שהוגדר, נוסף פריט לתפריט באמצעות הערך ב-android:label של מסנן ה-Intent בתור שם הפריט בתפריט, וסמל האפליקציה בתור סמל הפריט בתפריט. השיטה addIntentOptions() מחזירה את מספר הפריטים שנוספו לתפריט.
הוספת הפעילות לתפריטים אחרים
אתם יכולים להציע את השירותים של הפעילות שלכם לאפליקציות אחרות, כדי שהאפליקציה שלכם תיכלל בתפריט של אפליקציות אחרות – כך תהפכו את התפקידים שתיארנו קודם.
כדי שהאפליקציה תופיע בתפריטים של אפליקציות אחרות, צריך להגדיר מסנן Intent כרגיל, אבל לכלול את הערכים CATEGORY_ALTERNATIVE או CATEGORY_SELECTED_ALTERNATIVE, או את שניהם, בקטגוריית מסנן ה-Intent. כך זה נראה בדוגמה הבאה:
<intent-filter label="@string/resize_image"> ... <category android:name="android.intent.category.ALTERNATIVE" /> <category android:name="android.intent.category.SELECTED_ALTERNATIVE" /> ... </intent-filter>
מידע נוסף על כתיבת מסנני כוונות זמין במאמר כוונות ומסנני כוונות.