Dodaj menu

Wypróbuj sposób tworzenia wiadomości
Jetpack Compose to zalecany zestaw narzędzi UI na Androida. Dowiedz się, jak dodawać komponenty w narzędziu Compose

Menu to typowy element interfejsu w wielu rodzajach aplikacji. Aby zapewnić użytkownikom spójne i spójne środowisko, używaj interfejsów API Menu do prezentowania działań użytkowników i innych opcji w swoich działaniach.

Ilustracja pokazująca przykład rozszerzonego menu
Rysunek 1. Menu wyświetlane po kliknięciu ikony, które pojawi się pod ikoną rozszerzonego menu.

Z tego dokumentu dowiesz się, jak na wszystkich wersjach Androida utworzyć trzy podstawowe typy menu lub prezentacji działań:

Menu opcji i pasek aplikacji
Menu opcji to podstawowy zbiór elementów menu dotyczących aktywności. To miejsce, w którym wykonujesz działania, które mają globalny wpływ na aplikację, takie jak „Wyszukiwarka”, „Napisz e-maila” i „Ustawienia”.

Zobacz sekcję Tworzenie menu opcji.

Menu kontekstowe i tryb czynności kontekstowych
Menu kontekstowe to pływające menu, które pojawia się, gdy użytkownik naciśnie i przytrzyma element. Podaje działania, które wpływają na wybraną treść lub ramkę kontekstu.

W trybie działań kontekstowych na pasku u góry ekranu wyświetlane są działania wpływające na wybrane treści. Użytkownik może wybrać wiele elementów.

Zobacz sekcję Tworzenie menu kontekstowego.

Wyskakujące menu
Wyskakujące menu zawiera pionową listę elementów zakotwiczonych w widoku, który je wywołuje. Warto utworzyć dodatkowe czynności, które odnoszą się do określonej treści, lub opcje dotyczące drugiej części polecenia. Działania w wyskakującym menu nie mają bezpośredniego wpływu na odpowiednie treści – służą do tego działania kontekstowe. Wyskakujące menu jest natomiast przeznaczone do rozszerzonych działań związanych z regionami treści w Twojej aktywności.

Zapoznaj się z sekcją Tworzenie wyskakującego menu.

Zdefiniuj menu w pliku XML

Dla wszystkich typów menu Android zapewnia standardowy format XML do definiowania pozycji menu. Zamiast tworzyć menu w kodzie aktywności, zdefiniuj menu i wszystkie jego elementy w zasobie menu XML. Następnie możesz powiększyć zasób menu, wczytać go jako obiekt Menu, w swojej aktywności lub fragmencie.

Korzystanie z zasobu menu jest dobrym rozwiązaniem z tych powodów:

  • Struktura menu jest łatwiejsza do przedstawienia w formacie XML.
  • Oddziela on zawartość menu od kodu behawioralnego aplikacji.
  • Pozwala tworzyć alternatywne konfiguracje menu dla różnych wersji platformy, rozmiarów ekranu i innych konfiguracji przy użyciu platformy zasobów aplikacji.

Aby zdefiniować menu, utwórz plik XML w katalogu res/menu/ projektu i utwórz menu z tymi elementami:

<menu>
Definiuje element Menu, który jest kontenerem dla pozycji menu. Element <menu> musi być węzłem głównym pliku i może zawierać co najmniej 1 element <item> i <group>.
<item>
Tworzy element MenuItem reprezentujący pojedynczy element menu. Ten element może zawierać zagnieżdżony element <menu> służący do tworzenia podmenu.
<group>
Opcjonalny, niewidoczny kontener na elementy <item>. Pozwala dzielić pozycje menu na kategorie, aby miały wspólne właściwości, takie jak stan aktywności i widoczność. Więcej informacji znajdziesz w sekcji Tworzenie grupy menu.

Oto przykładowe menu o nazwie 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>

Element <item> obsługuje kilka atrybutów, których można użyć do określenia wyglądu i zachowania elementu. Pozycje w poprzednim menu zawierają te atrybuty:

android:id
Unikalny identyfikator zasobu dla danego elementu, dzięki któremu aplikacja może go rozpoznać, gdy użytkownik wybierze dany element.
android:icon
Odwołanie do elementu rysowanego, który ma być używany jako ikona elementu.
android:title
Odwołanie do ciągu znaków, które zostanie użyte jako tytuł elementu.
android:showAsAction
Specyfikacja określająca, kiedy i jak dany element wyświetla się jako działanie na pasku aplikacji.

To najważniejsze atrybuty, których używasz, ale jest ich znacznie więcej. Informacje o wszystkich obsługiwanych atrybutach znajdziesz w dokumentacji zasobów menu.

Możesz dodać podmenu do elementu w dowolnym menu, dodając element <menu> jako element podrzędny elementu <item>. Menu podrzędne są przydatne, gdy aplikacja ma wiele funkcji, które można uporządkować według tematów, takich jak elementy na pasku menu aplikacji na komputerze, takie jak Plik, Edytuj i Widok. Zobacz ten przykład:

<?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>

Aby użyć menu w aktywności, _inflate_ wybierz zasób menu, przekonwertuj zasób XML na programowalny obiekt za pomocą funkcji MenuInflater.inflate(). W sekcjach poniżej znajdziesz informacje o tym, jak zwiększać rozmiar menu w przypadku każdego typu menu.

Utwórz menu opcji

Menu opcji, tak jak to pokazane na ilustracji 1, zawiera działania i inne opcje związane z bieżącym kontekstem aktywności, np. „Wyszukiwanie”, „Napisz e-maila” i „Ustawienia”.

Ilustracja pokazująca pasek aplikacji Arkusze Google
Rysunek 2. Aplikacja Arkusze Google z kilkoma przyciskami, w tym menu rozszerzonym działania.

Elementy w menu opcji możesz zadeklarować z poziomu podklasy Activity lub podklasy Fragment. Jeśli zarówno Twoja aktywność, jak i fragmenty deklarują elementy w menu opcji, elementy te będą połączone w interfejsie. Jako pierwsze pojawiają się elementy aktywności, a potem elementy dla każdego fragmentu w kolejności, w jakiej zostały one dodane do działania. W razie potrzeby możesz zmienić kolejność pozycji menu, dodając atrybut android:orderInCategory w każdym elemencie <item>, który chcesz przenieść.

Aby określić menu opcji aktywności, zastąp parametr onCreateOptionsMenu(). Fragmenty kodu mają własne onCreateOptionsMenu()wywołanie zwrotne. Ta metoda pozwala powiększyć zasób menu zdefiniowany w pliku XML do wartości Menu podanej w wywołaniu zwrotnym. Widać to w tym przykładzie:

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;
}

Możesz też dodawać pozycje menu za pomocą add() i pobierać elementy za pomocą findItem(), aby zmodyfikować ich właściwości za pomocą interfejsów API MenuItem.

Obsługa zdarzeń kliknięcia

Gdy użytkownik wybierze element z menu opcji, w tym działania na pasku aplikacji, system wywoła metodę onOptionsItemSelected() aktywności. Ta metoda przekazuje wybraną MenuItem. Możesz wskazać ten element, wywołując metodę getItemId(), która zwraca unikalny identyfikator pozycji menu zdefiniowany za pomocą atrybutu android:id w zasobie menu lub za pomocą liczby całkowitej podanej w metodzie add(). Możesz go dopasować do znanych pozycji menu, aby wykonać odpowiednie działanie.

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);
    }
}

Gdy przejdziesz do pozycji menu, zwróć true. Jeśli nie zajmujesz się tą pozycją menu, wywołaj implementację superklasy onOptionsItemSelected(). Domyślna implementacja zwraca wartość „false” (fałsz).

Jeśli aktywność obejmuje fragmenty, system najpierw wywołuje onOptionsItemSelected() dla aktywności, a następnie dla każdego fragmentu w kolejności ich dodania, aż jeden zwróci wartość true lub wszystkie fragmenty.

Zmieniaj pozycje menu podczas działania

Gdy system wywoła funkcję onCreateOptionsMenu(), zachowa wystąpienie wypełnionej przez Ciebie Menu i nie wywoła ponownie onCreateOptionsMenu(), chyba że menu zostanie unieważnione. onCreateOptionsMenu() należy jednak używać tylko do tworzenia początkowego stanu menu, a nie do wprowadzania zmian w trakcie cyklu życia działania.

Jeśli chcesz zmodyfikować menu opcji na podstawie zdarzeń występujących w cyklu życia aktywności, możesz to zrobić za pomocą metody onPrepareOptionsMenu(). Ta metoda przekazuje Ci obiekt Menu w obecnej postaci, aby umożliwić Ci jego modyfikowanie, np. przez dodanie, usunięcie lub wyłączenie elementów. Fragmenty kodu zapewniają też onPrepareOptionsMenu() wywołanie zwrotne.

Menu opcji jest zawsze otwarte, gdy elementy menu znajdują się na pasku aplikacji. Gdy wystąpi zdarzenie i chcesz zaktualizować menu, wywołaj invalidateOptionsMenu(), by zażądać wywołania systemowego onPrepareOptionsMenu().

Tworzenie menu kontekstowego

Obraz przedstawiający pływające menu kontekstowe
Rysunek 3. Pływające menu kontekstowe.

Menu kontekstowe oferuje działania, które wpływają na konkretny element lub ramkę kontekstową w interfejsie. Menu kontekstowe możesz podać dla dowolnego widoku, ale najczęściej używa się go w kolekcjach elementów RecylerView lub innych widoków, w których użytkownik może wykonywać bezpośrednie działania na poszczególnych elementach.

Działania kontekstowe można udostępniać na 2 sposoby:

  • w pływającym menu kontekstowym – Menu wyświetla się w postaci pływającej listy pozycji menu, podobnie jak w przypadku okna dialogowego, gdy użytkownik naciśnie i przytrzymasz widok, który deklaruje obsługę menu kontekstowego. Użytkownicy mogą wykonywać działania kontekstowe na jednym elemencie naraz.
  • w trybie działań kontekstowych, Ten tryb jest implementacją systemową funkcji ActionMode, w której u góry ekranu wyświetla się pasek działań kontekstowych(CAB) z działaniami, które wpływają na wybrane elementy. Gdy ten tryb jest aktywny, użytkownicy mogą wykonywać działania na wielu elementach jednocześnie, jeśli aplikacja to obsługuje.

Uwaga: menu kontekstowe nie obsługuje skrótów elementów ani ikon elementów.

Tworzenie pływającego menu kontekstowego

Aby udostępnić pływające menu kontekstowe, wykonaj te czynności:

  1. Zarejestruj obiekt View, z którym powiązane jest menu kontekstowe, wywołując registerForContextMenu() i przekazując do niego View.

    Jeśli Twoja aktywność korzysta z elementu RecyclerView i chcesz, aby każda pozycja udostępniała to samo menu kontekstowe, zarejestruj wszystkie elementy w menu kontekstowym, przekazując RecyclerView do registerForContextMenu().

  2. Zaimplementuj metodę onCreateContextMenu() w Activity lub Fragment.

    Gdy zarejestrowany widok otrzyma zdarzenie naciśnięcia i przytrzymania, system wywoła metodę onCreateContextMenu(). W tym miejscu definiuje się elementy menu, zwykle przez poszerzenie zasobu menu, jak w tym przykładzie:

    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 pozwala rozszerzyć menu kontekstowe z poziomu zasobu menu. Parametry metody wywołania zwrotnego obejmują obiekt View wybrany przez użytkownika i obiekt ContextMenu.ContextMenuInfo, który zawiera dodatkowe informacje o wybranym elemencie. Jeśli Twoja aktywność ma kilka widoków, z których każdy zawiera inne menu kontekstowe, możesz użyć tych parametrów, aby określić, które menu kontekstowe należy zwiększyć.

  3. Wdróż onContextItemSelected() zgodnie z poniższym przykładem. Gdy użytkownik wybiera pozycję w menu, system wywołuje tę metodę, by umożliwić Ci wykonanie odpowiedniej czynności.

    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);
            }
        }
        

    Metoda getItemId() wysyła zapytanie o identyfikator wybranego elementu menu, który przypisujesz do każdej pozycji menu w pliku XML za pomocą atrybutu android:id, jak pokazano w sekcji Definiowanie menu w pliku XML.

    Gdy przejdziesz do pozycji menu, zwróć true. Jeśli nie obsługujesz tej pozycji menu, przekaż ją do implementacji klasy nadrzędnej. Jeśli aktywność zawiera fragmenty, najpierw otrzymuje to wywołanie zwrotne. Po wywołaniu nieobsługiwanej klasy superklasy system przekazuje zdarzenie do odpowiedniej metody wywołania zwrotnego w każdym fragmencie, po kolei, w kolejności dodawania fragmentów, aż do zwrócenia wartości true lub false. Domyślne implementacje Activity i android.app.Fragment zwracają false, więc zawsze wywołaj klasę nadrzędną, gdy nie jest obsługiwana.

Użyj trybu czynności kontekstowej

Tryb działań kontekstowych to implementacja systemowa ActionMode, która koncentruje interakcje użytkownika na wykonywaniu działań kontekstowych. Gdy użytkownik włączy ten tryb, wybierając element, u góry ekranu pojawi się pasek działań kontekstowych pokazujący działania, które użytkownik może wykonać na wybranych elementach. Gdy ten tryb jest włączony, użytkownik może zaznaczyć wiele elementów (o ile aplikacja obsługuje tę funkcję) i odznaczać je, aby kontynuować nawigowanie w obrębie aktywności. Tryb działań jest wyłączony, a pasek działań kontekstowych znika, gdy użytkownik odznaczy wszystkie elementy, kliknie przycisk Wstecz lub kliknie działanie Gotowe z lewej strony paska.

W przypadku widoków z działaniami kontekstowymi tryb działań kontekstowych jest zwykle wywoływany, gdy wystąpi co najmniej jedno z tych 2 zdarzeń:

  • Użytkownik klika i przytrzymuje widok.
  • Użytkownik zaznacza pole wyboru lub podobny komponent interfejsu w widoku.

Sposób, w jaki aplikacja wywołuje tryb działania kontekstowego i określa działanie każdego działania, zależy od projektu. Są 2 wzory:

  • Dla działań kontekstowych dotyczących poszczególnych, dowolnych widoków.
  • W przypadku zbiorczych działań kontekstowych dotyczących grup elementów w elemencie RecyclerView, które umożliwiają użytkownikowi wybranie wielu elementów i wykonanie na nich działania.

W sekcjach poniżej opisano konfigurację wymaganą w każdym scenariuszu.

Włącz tryb działań kontekstowych w poszczególnych widokach

Jeśli chcesz wywoływać tryb działania kontekstowego tylko wtedy, gdy użytkownik wybierze określone widoki, wykonaj te czynności:

  1. Zaimplementuj interfejs ActionMode.Callback zgodnie z poniższym przykładem. W jego metodach wywołania zwrotnego możesz określić działania dla kontekstowego paska działań, odpowiadać na zdarzenia kliknięcia dotyczące działań oraz obsługiwać inne zdarzenia cyklu życia dla trybu działania.

    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;
            }
        };
        

    Te wywołania zwrotne zdarzeń są prawie takie same jak wywołania zwrotne menu opcji z tą różnicą, że każda z nich przekazuje również obiekt ActionMode powiązany ze zdarzeniem. Za pomocą interfejsów API ActionMode możesz wprowadzać różne zmiany w CAB, na przykład zmieniać tytuł i podtytuł za pomocą właściwości setTitle() i setSubtitle(), co jest przydatne do określania liczby wybranych elementów.

    Poprzedni przykład ustawia zmienną actionMode na null po zniszczeniu trybu działania. W następnym kroku zobaczysz, jak jest inicjowana i jak może pomóc zapisanie zmiennej członkowskiej w aktywności lub fragmencie.

  2. Wywołaj startActionMode(), gdy chcesz wyświetlić pasek, na przykład gdy użytkownik naciśnie i przytrzymasz widok.

    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;
            }
        });
        

    Gdy wywołujesz startActionMode(), system zwraca utworzony element ActionMode. Dzięki zapisaniu go w zmiennej użytkownika możesz wprowadzać zmiany na kontekstowym pasku działań w odpowiedzi na inne zdarzenia. W poprzednim przykładzie używamy ActionMode, aby zagwarantować, że instancja ActionMode nie zostanie odtworzona, jeśli jest już aktywna. Aby to zrobić, przed uruchomieniem trybu działania sprawdź, czy element ma wartość null.

Utwórz wyskakujące menu

Obraz przedstawiający wyskakujące menu w aplikacji Gmail zakotwiczone do rozszerzonego przycisku w prawym górnym rogu.
Rysunek 4. Wyskakujące menu w aplikacji Gmail, zakotwiczone na rozszerzonym przycisku w prawym górnym rogu.

PopupMenu to menu modalne zakotwiczone na elemencie View. Pojawia się pod widokiem zakotwiczonym, jeśli jest wystarczająco dużo miejsca, lub nad widokiem, jeśli nie jest widoczny. Jest to przydatne, gdy:

  • Udostępnianie rozszerzonego menu dla działań odnoszących się do określonych treści, takich jak nagłówki e-maili w Gmailu, jak pokazano na rys. 4.
  • dodanie drugiej części zdania polecenia, na przykład przycisku Dodaj, który powoduje wyświetlenie menu z różnymi opcjami Dodaj.
  • Udostępnij menu podobne do elementu Spinner, które nie zawiera trwałego wyboru.

Jeśli zdefiniujesz menu w formacie XML, wyświetli się ono w ten sposób:

  1. Utwórz instancję PopupMenu za pomocą konstruktora, który pobiera bieżącą aplikację Context i View, z którym zakotwiczone jest menu.
  2. Użyj polecenia MenuInflater, aby rozszerzyć zasób menu do obiektu Menu zwróconego przez funkcję PopupMenu.getMenu().
  3. Będziesz dzwonić pod numer PopupMenu.show().

Oto przykład:

<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" />

Działanie może wtedy wyświetlić wyskakujące menu:

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();
});

Menu jest zamykane, gdy użytkownik wybierze pozycję lub kliknie poza obszarem menu. Możesz nasłuchiwać zdarzenia odrzucenia za pomocą PopupMenu.OnDismissListener.

Obsługa zdarzeń kliknięcia

Aby wykonać działanie, gdy użytkownik wybierze pozycję menu, zaimplementuj interfejs PopupMenu.OnMenuItemClickListener i zarejestruj go w PopupMenu, wywołując setOnMenuItemclickListener(). Gdy użytkownik wybiera element, system wywołuje wywołanie zwrotne onMenuItemClick() w interfejsie.

Widać to w tym przykładzie:

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;
    }
}

Utwórz grupę menu

Grupa menu to zbiór pozycji menu, które mają wspólne cechy. Dzięki grupie możesz:

Grupę możesz utworzyć, zagnieżdżając elementy <item> w elemencie <group> w zasobie menu lub podając identyfikator grupy za pomocą metody add().

Oto przykład zasobu menu zawierającego grupę:

<?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>

Elementy w grupie są wyświetlane na tym samym poziomie co pierwszy element – wszystkie 3 elementy w menu są elementami potocznymi. Możesz jednak modyfikować cechy 2 elementów w grupie, odwołując się do identyfikatora grupy i używając poprzednich metod. System nigdy nie rozdziela też zgrupowanych elementów. Jeśli na przykład zadeklarujesz android:showAsAction="ifRoom" dla każdego elementu, oba te elementy pojawią się na pasku działań lub oba w obszarze działań.

Używaj pozycji menu, które można zaznaczyć

Rysunek 5. Podmenu z elementami do zaznaczenia.

Menu może służyć jako interfejs do włączania i wyłączania opcji, a także za pomocą pól wyboru dla samodzielnych opcji lub przycisków dla grup opcji wzajemnie wykluczających się. Rysunek 5 przedstawia menu podrzędne z elementami, które można zaznaczyć za pomocą opcji.

Zachowanie, które można sprawdzić w przypadku poszczególnych pozycji menu, możesz określić za pomocą atrybutu android:checkable w elemencie <item> lub dla całej grupy za pomocą atrybutu android:checkableBehavior w elemencie <group>. Na przykład wszystkie pozycje w tej grupie menu można zaznaczyć za pomocą opcji:

<?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>

Atrybut android:checkableBehavior akceptuje jeden z tych atrybutów:

single
Można zaznaczyć tylko jeden element z grupy, co spowoduje utworzenie przycisków.
all
Można zaznaczyć wszystkie elementy, co spowoduje wyświetlenie pól wyboru.
none
Brak elementów do sprawdzenia.

Możesz zastosować do elementu domyślnie zaznaczony stan „zaznaczony” za pomocą atrybutu android:checked w elemencie <item> i zmienić go w kodzie za pomocą metody setChecked().

Po zaznaczeniu elementu, który można zaznaczyć, system wywołuje odpowiednią metodę wywołania zwrotnego wybranego elementu, na przykład onOptionsItemSelected(). W tym miejscu ustawia się stan pola wyboru, ponieważ jego stan nie zmienia się automatycznie. Możesz przesłać zapytanie o bieżący stan elementu (w postaci, w jakiej był przed wybraniem go przez użytkownika), za pomocą funkcji isChecked(), a następnie ustawić stan zaznaczonego za pomocą setChecked(). W tym przykładzie widać:

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);
    }
}

Jeśli nie ustawisz stanu zaznaczonego w ten sposób, jego widoczność nie zmieni się, gdy użytkownik wybierze pole wyboru. Gdy ustawisz stan, działanie to zachowuje zaznaczony stan elementu, dzięki czemu, gdy użytkownik otworzy menu później, ustawiony przez Ciebie stan będzie widoczny.

Dodaj pozycje menu na podstawie intencji

Czasem chcesz, aby pozycja menu uruchamiała działanie za pomocą polecenia Intent, niezależnie od tego, czy jest to działanie w Twojej aplikacji czy w innej. Jeśli wiesz, czego chcesz użyć, i masz określony element menu, który inicjuje intencję, możesz wykonać intencję za pomocą metody startActivity() w ramach odpowiedniej metody wywołania zwrotnego wybranego elementu, na przykład wywołania zwrotnego onOptionsItemSelected().

Jeśli jednak nie masz pewności, czy na urządzeniu użytkownika znajduje się aplikacja, która obsługuje intencję, dodanie pozycji menu, która je wywołuje, może spowodować, że pozycja menu nie będzie działać, ponieważ intencja może nie odpowiadać działaniu. Aby rozwiązać ten problem, Android umożliwia dynamiczne dodawanie pozycji menu do menu, gdy znajdzie na urządzeniu działania, które obsługują Twoje intencje.

Aby dodać pozycje menu na podstawie dostępnych działań, które akceptują intencję, wykonaj te czynności:

  1. Zdefiniuj intencję za pomocą kategorii CATEGORY_ALTERNATIVE lub CATEGORY_SELECTED_ALTERNATIVE bądź obu tych elementów, i dodaj inne wymagania.
  2. Zadzwoń pod numer Menu.addIntentOptions(). Android wyszukuje wtedy aplikacje, które mogą to zrobić, i dodaje je do menu.

Jeśli nie masz zainstalowanych aplikacji, które spełniałyby tę intencję, elementy menu nie są dodawane.

Widać to w tym przykładzie:

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;
}

W przypadku każdego znalezionego działania, które dostarcza filtr intencji pasujący do zdefiniowanej intencji, pojawia się element menu, w którym wartość w filtrze intencji (android:label) jest używana jako tytuł, a ikona aplikacji jako ikona elementu menu. Metoda addIntentOptions() zwraca liczbę dodanych pozycji menu.

Pozwól na dodawanie aktywności do innych menu

Możesz oferować innym aplikacjom usługi związane z aktywnością, dzięki czemu Twoja aplikacja będzie widoczna w menu innych osób – odwrotnie będzie w przypadku opisanych wcześniej ról.

Aby znaleźć się w innych menu aplikacji, zdefiniuj filtr intencji w zwykły sposób, ale w przypadku kategorii filtra intencji uwzględnij wartość CATEGORY_ALTERNATIVE lub CATEGORY_SELECTED_ALTERNATIVE albo obie te wartości. Widać to w tym przykładzie:

<intent-filter label="@string/resize_image">
    ...
    <category android:name="android.intent.category.ALTERNATIVE" />
    <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
    ...
</intent-filter>

Więcej informacji o tworzeniu filtrów intencji znajdziesz w artykule Intencje i filtry intencji.