הוספת תפריטים

רוצה לנסות את שיטת הכתיבה?
'Jetpack פיתוח נייטיב' היא ערכת הכלים המומלצת לממשק המשתמש ל-Android. מידע על הוספת רכיבים לכתיבה.

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

תמונה שמציגה דוגמה של אפשרויות נוספות
איור 1. תפריט שמופעל על ידי הקשה על סמל, שמופיעה מתחת לסמל האפשרויות הנוספות.

המסמך הזה מראה איך ליצור את שלושת הסוגים הבסיסיים של תפריטים או מצגות של פעולות בכל הגרסאות של Android:

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

צפייה בתפריט 'יצירה של אפשרויות' .

תפריט הקשר ומצב פעולה לפי הקשר
תפריט הקשר הוא תפריט צף שמופיעה כאשר המשתמש מבצע נגיעה ללחוץ על רכיב. הוא מציגה פעולות שמשפיעות על מסגרת ההקשר או על התוכן שנבחר.

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

ניתן לעיין בתפריט ההקשר ליצירת תפריט לפי הקשר. .

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

פרטים נוספים זמינים בקטע יצירת תפריט קופץ.

הגדרת תפריט ב-XML

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

מומלץ להשתמש במשאב של תפריטים מהסיבות הבאות:

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

כדי להגדיר תפריט, צריך ליצור קובץ XML בתוך הספרייה res/menu/ ויוצרים את התפריט באמצעות האפשרויות הבאות רכיבים:

<menu>
מגדירה Menu, שהוא מאגר לאפשרויות בתפריט. א' הרכיב <menu> חייב להיות הצומת של הרמה הבסיסית (root) של הקובץ, יכול להכיל ערך אחד או יותר מסוג <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
הפניה לפריט גרפי שניתן להשתמש בו כסמל של הפריט.
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>

כדי להשתמש בתפריט בפעילות שלך, _inflate_ משאב התפריט, ממיר את משאב ה-XML לאובייקט שניתן לתכנות באמצעות MenuInflater.inflate() בקטעים הבאים מוסבר איך להגדיל את התפריט לפי סוג התפריט.

יצירה של תפריט אפשרויות

תפריט האפשרויות, כמו זה שמוצג באיור 1, הוא המקום שבו פעולות ואפשרויות אחרות שרלוונטיות להקשר הנוכחי של הפעילות, כמו 'חיפוש', "כתיבת אימייל," ו'הגדרות'.

תמונה שמוצג בה סרגל האפליקציות של אפליקציית Google Sheets
איור 2. אפליקציית Google Sheets, שמוצגת כמה לחצנים, כולל לחצן 'אפשרויות נוספות'.

אפשר להצהיר על פריטים בתפריט האפשרויות מתוך Activity מחלקה משנית Fragment של מחלקה משנית. אם גם הפעילות וגם המקטעים שלך מצהירים על פריטים עבור תפריט האפשרויות, הפריטים משולבים בממשק המשתמש. פריטי הפעילות מופיעים הראשון, ואחריו כל המקטעים, לפי הסדר שבו נוספים לפעילות. במידת הצורך, אפשר להזמין מחדש את האפשרויות בתפריט עם המאפיין android:orderInCategory בכל <item> שצריך להעביר.

כדי לציין את תפריט האפשרויות של פעילות מסוימת, משנים את ההגדרה onCreateOptionsMenu() מקטעים מספקים משלהם 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() . השיטה הזו מעבירה את MenuItem שנבחרו. אפשר לזהות את הפריט באמצעות התקשרות getItemId(), שמחזיר את המזהה הייחודי של האפשרות בתפריט, המוגדר באמצעות הפונקציה המאפיין android:id במשאב התפריט או עם מספר שלם שצוין ל-method 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() פעולת ההטמעה שמוגדרת כברירת מחדל מחזירה לא נכון.

אם הפעילות שלך כוללת מקטעים, המערכת קודם קוראת onOptionsItemSelected() לפעילות ואז לכל מקטע לפי הסדר שבו המקטעים נוספו, עד שאחד המקטעים יחזיר true או כל המקטעים נקראים.

שינוי אפשרויות בתפריט בזמן הריצה

אחרי שהמערכת קוראת ל-onCreateOptionsMenu(), היא שומרת מופע של Menu שאתם מאכלסים ולא קוראים onCreateOptionsMenu() שוב, אלא אם התפריט לא תקף. עם זאת, אפשר להשתמש ב-onCreateOptionsMenu() רק כדי ליצור את התפריט הראשוני ולא לבצע שינויים במהלך מחזור החיים של הפעילות.

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

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

יצירת תפריט הקשרי

תמונה שמוצג בה תפריט הקשר צף
איור 3. תפריט הקשר צף.

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

יש שתי דרכים לספק פעולות לפי הקשר:

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

הערה: בתפריט ההקשר אין תמיכה במקשי קיצור של פריטים ובסמלי פריטים.

יצירת תפריט הקשר צף

כדי לספק תפריט הקשר צף, מבצעים את הפעולות הבאות:

  1. צריך לרשום את View שתפריט ההקשר משויך אליו שיחות registerForContextMenu() ומעבירים את View.

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

  2. ליישם את onCreateContextMenu() ל-Activity או Fragment.

    כשהתצוגה הרשומה מקבלת מגע & אירוע hold, המערכת קוראת אמצעי התשלום 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 מאפשרת להגדיל את תפריט ההקשר מתוך משאב של תפריט. שיטת הקריאה החוזרת הפרמטרים כוללים את View שהמשתמש בוחר ו ContextMenu.ContextMenuInfo שמספק מידע נוסף על הפריט שנבחר. אם המיקום לפעילות שלכם יש כמה תצוגות, שכל אחת מהן מספקת תפריט הקשר שונה, אפשר להשתמש בפרמטרים האלה כדי לקבוע איזה תפריט הקשר צריך לניפוח.

  3. יישום 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() method מפעילה שאילתות על המזהה של האפשרות שנבחרה בתפריט, שמקצים לכל אחד מהם פריט בתפריט ב-XML באמצעות המאפיין android:id, כפי שמוצג הגדרת תפריט ב-XML.

    אם האפשרות בתפריט טופלה בהצלחה, הפונקציה מחזירה את הערך true. אם המיקום לא מטפלים באפשרות בתפריט, מעבירים את האפשרות בתפריט למחלקה-העל יישום בפועל. אם הפעילות שלך כוללת מקטעים, הפעילות מקבלת את הקריאה החוזרת הזאת תחילה. באמצעות קריאה למחלקה-העל כשהטיפול בה לא מטופל, המערכת מעביר את האירוע לשיטת הקריאה החוזרת המתאימה בכל מקטע, אחד ב- זמן, לפי הסדר שבו התווסף כל מקטע, עד true או השדה false הוחזר. הטמעות ברירת מחדל עבור Activity ו-android.app.Fragment החזרה false, לכן תמיד צריך לקרוא למחלקת העל כשלא מטפלים בה.

שימוש במצב פעולה לפי הקשר

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

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

  • המשתמש מבצע נגיעה ו את התצוגה.
  • המשתמש בוחר בתיבת סימון או ברכיב דומה של ממשק המשתמש בתצוגה.

האופן שבו האפליקציה מפעילה את מצב הפעולה לפי הקשר ומגדירה את ההתנהגות של כל פעולה תלויה בעיצוב שלכם. יש שני עיצובים:

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

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

הפעלת מצב פעולה לפי הקשר בתצוגות ספציפיות

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

  1. מטמיעים את הממשק של ActionMode.Callback כפי שמוצג בדוגמה הבאה. ב-methods של הקריאה החוזרת (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;
            }
        };
        

    הקריאות החוזרות (callback) של האירועים האלה כמעט זהות לקריאות החוזרות של תפריט האפשרויות, למעט כל אחת מהאפשרויות הוא גם מעביר את האובייקט ActionMode שמשויך לאירוע. ניתן להשתמש בממשקי API של ActionMode כדי לבצע שינויים שונים CAB, למשל תיקון השם והכותרת משנה עם setTitle() וגם setSubtitle(), וזה שימושי כדי לציין כמה פריטים נבחרו.

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

  2. שיחת טלפון 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, שמוצמד ללחצן האפשרויות הנוספות בפינה השמאלית העליונה.
איור 4. תפריט קופץ באפליקציית Gmail, שמוצמד ללחצן האפשרויות הנוספות בפינה השמאלית העליונה.

PopupMenu הוא תפריט מודאלי שמקושר אל View. היא מופיעה מתחת לעוגן אם יש מקום, או מעל התצוגה, אחרת. זה שימושי הבאים:

  • הוספת תפריט אפשרויות נוספות לפעולות שקשורות אל תוכן ספציפי, כמו הכותרות של האימיילים ב-Gmail, שמוצג באיור 4.
  • הצגת חלק שני של משפט פקודה, כמו לחצן שמסומן לחיצה על Add יוצרת תפריט קופץ עם אפשרויות שונות של Add. אפשרויות.
  • הצגת תפריט שדומה Spinner שלא שומרת על בחירה מתמשכת.

אם הגדרתם את התפריט ב-XML, כך תוכלו להציג התפריט הקופץ:

  1. יצירת אובייקט של PopupMenu באמצעות ה-constructor שלו, שלוקחת האפליקציה הנוכחית Context וגם View שאליו התפריט מוצמד.
  2. שימוש ב-MenuInflater כדי להגדיל את משאב התפריט אובייקט Menu הוחזר על ידי PopupMenu.getMenu().
  3. התקשרות אל 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(). כשמשתמש בוחר פריט, המערכת שולחת קריאה onMenuItemClick() קריאה חוזרת (callback) בממשק.

אפשר לראות זאת בדוגמה הבאה:

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. תפריט משנה עם פריטים שאפשר לסמן.

תפריט יכול להיות שימושי כממשק להפעלה וכיבוי של אפשרויות, באמצעות תיבת סימון של אפשרויות נפרדות, או לחצני בחירה לקבוצות של אפשרויות בלעדיות. איור 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() במהלך שיטת הקריאה החוזרת המתאימה לפריט שנבחר, כמו התקשרות חזרה onOptionsItemSelected().

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

כדי להוסיף אפשרויות בתפריט על סמך פעילויות זמינות שמקבלות כוונה, צריך לבצע את הפעולות הבאות: הבאים:

  1. יש להגדיר כוונה באמצעות הקטגוריה CATEGORY_ALTERNATIVE או CATEGORY_SELECTED_ALTERNATIVE, או לשניהם, וכל דרישה אחרת.
  2. שיחת טלפון 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. מוגדר, פריט תפריט מתווסף באמצעות הערך שבמסנן Intent android:label בתור הכותרת של האפשרות בתפריט וסמל האפליקציה בתור התפריט סמל הפריט. השיטה 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>

מידע נוסף על כתיבת מסנני Intent זמין כאן כוונות וכוונות מסננים.