Добавить меню

Попробуйте Compose
Jetpack Compose – это рекомендуемый набор инструментов для создания пользовательского интерфейса в Android. Узнайте, как добавлять компоненты в Compose.

Меню – это распространенный компонент пользовательского интерфейса во многих типах приложений. Чтобы обеспечить привычный и единообразный пользовательский интерфейс, используйте API Menu для представления действий пользователя и других параметров в ваших действиях.

Изображение, на котором показан пример дополнительного меню
Рисунок 1. Меню, которое открывается при нажатии на значок и появляется под значком дополнительного меню.

В этом документе показано, как создать три основных типа меню или презентаций действий во всех версиях Android:

Меню параметров и панель приложения
Меню параметров – это основной набор пунктов меню для действия. В ней размещаются действия, которые влияют на приложение в целом, например "Поиск", "Написать письмо" и "Настройки".

Подробнее о том, как создать меню параметров…

Контекстное меню и режим контекстных действий
Контекстное меню – это плавающее меню, которое появляется, когда пользователь нажимает на элемент и удерживает его. Она содержит действия, которые влияют на выбранный контент или контекстный фрейм.

В режиме контекстных действий на панели в верхней части экрана отображаются задачи, связанные с выбранным контентом. Пользователь может выбрать несколько задач.

Подробнее о том, как создать контекстное меню…

Всплывающее меню
Всплывающее меню – это вертикальный список элементов, привязанный к представлению, которое его вызывает. Оно подходит для дополнительных действий, связанных с определенным контентом, или для выбора параметров второй части команды. Действия во всплывающем меню не влияют напрямую на соответствующий контент – для этого предназначены контекстные действия. Оно предназначено для дополнительных действий, связанных с определенными областями контента в вашем действии.

Подробнее о том, как создать всплывающее меню…

Как определить меню в XML

Для всех типов меню Android предоставляет стандартный формат XML, позволяющий определять пункты меню. Вместо того чтобы создавать меню в коде объекта activity, определите меню и все его элементы в 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
Ссылка на графический объект, который будет использоваться в качестве значка элемента.
android:title
Ссылка на строку, которая будет использоваться в качестве названия объекта.
android:showAsAction
Спецификация, определяющая, когда и как этот элемент появляется в качестве задачи на панели приложения.

Это самые важные атрибуты, но есть и другие. Информацию обо всех поддерживаемых атрибутах можно найти в документации по ресурсу Menu.

Вы можете добавить подменю к пункту в любом меню, добавив элемент <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 Таблицы
Рисунок 2. Приложение Google Таблицы с несколькими кнопками, включая кнопку "Ещё".

Вы можете объявить элементы для меню параметров из подкласса Activity или Fragment. Если и в действии, и во фрагментах объявлены элементы для меню параметров, они объединяются в интерфейсе. Сначала отображаются элементы объекта activity, а затем – элементы каждого фрагмента в порядке их добавления в объект activity. При необходимости вы можете изменить порядок пунктов меню с помощью атрибута 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() объекта activity. Этот метод передает выбранный 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.

Если в объекте activity есть фрагменты, система сначала вызывает метод onOptionsItemSelected() для объекта activity, а затем для каждого фрагмента в порядке их добавления, пока один из них не вернет значение true или не будут вызваны все фрагменты.

Изменение пунктов меню во время выполнения

После вызова onCreateOptionsMenu() система сохраняет экземпляр Menu, который вы заполняете, и не вызывает onCreateOptionsMenu() снова, если меню не становится недействительным. Однако используйте onCreateOptionsMenu() только для создания начального состояния меню, а не для внесения изменений в течение жизненного цикла объекта activity.

Если вы хотите изменить меню параметров на основе событий, которые происходят в течение жизненного цикла объекта activity, вы можете сделать это в методе onPrepareOptionsMenu(). Этот метод передает вам объект Menu в его текущем виде, чтобы вы могли изменить его, например добавить, удалить или отключить элементы. Фрагменты также предоставляют обратный вызов onPrepareOptionsMenu().

Если пункты меню параметров представлены на панели приложения, оно считается всегда открытым. Когда происходит событие и вы хотите обновить меню, вызовите invalidateOptionsMenu(), чтобы запросить у системы вызов onPrepareOptionsMenu().

Как создать контекстное меню

Изображение плавающего контекстного меню
Рисунок 3. Плавающее контекстное меню.

Контекстное меню предлагает действия, которые влияют на конкретный элемент или контекстный фрейм в пользовательском интерфейсе. Контекстное меню можно добавить для любого представления, но чаще всего оно используется для элементов в RecylerView или других коллекциях представлений, в которых пользователь может выполнять прямые действия с каждым элементом.

Есть два способа предоставить контекстные действия:

  • В плавающем контекстном меню. Меню появляется в виде плавающего списка пунктов меню, похожего на диалоговое окно, когда пользователь нажимает и удерживает представление, которое объявляет о поддержке контекстного меню. Контекстное действие можно выполнить только с одним объектом за раз.
  • В режиме контекстных действий. Этот режим представляет собой системную реализацию ActionMode, которая показывает панель контекстных действий в верхней части экрана с задачами, влияющими на выбранные элементы. Когда этот режим активен, пользователи могут выполнять действия с несколькими элементами одновременно, если ваше приложение поддерживает такую возможность.

Примечание. Контекстное меню не поддерживает ярлыки и значки элементов.

Как создать плавающее контекстное меню

Чтобы создать плавающее контекстное меню, выполните следующие действия:

  1. Зарегистрируйте View, с которым связано контекстное меню, вызвав registerForContextMenu() и передав ему View.

    Если в вашем действии используется RecyclerView и вы хотите, чтобы для каждого элемента предоставлялось одно и то же контекстное меню, зарегистрируйте все элементы для контекстного меню, передав RecyclerView в registerForContextMenu().

  2. Реализуйте метод 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 позволяет развернуть контекстное меню из ресурса меню. Параметры метода обратного вызова включают 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() запрашивает идентификатор выбранного пункта меню, который вы назначаете каждому пункту меню в XML с помощью атрибута android:id, как показано в разделе Определение меню в XML.

    Если пункт меню обработан успешно, возвращается true. Если вы не обрабатываете пункт меню, передайте его реализации надкласса. Если в операции есть фрагменты, она сначала получает этот обратный вызов. Если событие не обработано, система вызывает надкласс и передает событие соответствующему методу обратного вызова в каждом фрагменте по очереди в порядке добавления фрагментов, пока не будет возвращено значение true или false. Реализации по умолчанию для Activity и android.app.Fragment возвращают false, поэтому всегда вызывайте надкласс, если событие не обработано.

Как использовать режим контекстных действий

Режим контекстных действий – это системная реализация ActionMode, которая позволяет пользователю выполнять контекстные действия. Когда пользователь включает этот режим, выбрав элемент, в верхней части экрана появляется панель контекстных действий, на которой представлены действия, которые пользователь может выполнить с выбранными элементами. В этом режиме пользователь может выбрать несколько элементов, если ваше приложение поддерживает такую возможность, отменить выбор элементов и продолжить навигацию в рамках действия. Режим действий отключается, а панель контекстных действий исчезает, когда пользователь отменяет выбор всех элементов, нажимает кнопку "Назад" или выбирает действие Готово в левой части панели.

Для представлений, которые предоставляют контекстные действия, вы обычно вызываете режим контекстных действий, когда происходит одно или оба из этих двух событий:

  • Пользователь нажимает на область просмотра и удерживает ее.
  • Пользователь устанавливает флажок или выбирает похожий компонент интерфейса в представлении.

То, как приложение вызывает режим контекстных действий и определяет поведение для каждого действия, зависит от вашего дизайна. Есть два варианта дизайна:

  • Для контекстных действий в отдельных произвольных представлениях.
  • Для контекстных действий с группами объектов в RecyclerView, позволяющих пользователю выбрать несколько объектов и выполнить с ними действие.

В следующих разделах описана настройка, необходимая для первого сценария.

Как включить режим контекстных действий для отдельных представлений

Если вы хотите вызывать режим контекстных действий, только когда пользователь выбирает определенные представления, сделайте следующее:

  1. Реализуйте интерфейс 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;
            }
        };
        

    Эти обратные вызовы событий практически идентичны обратным вызовам для меню параметров, за исключением того, что каждый из них также передает объект ActionMode, связанный с событием. С помощью API ActionMode можно вносить различные изменения в контекстную панель действий, например изменять заголовок и подзаголовок с помощью setTitle() и setSubtitle(), что полезно для указания количества выбранных элементов.

    В приведенном выше примере переменной actionMode присваивается значение null, когда режим действий закрывается. На следующем шаге вы узнаете, как инициализировать этот объект и как сохранить переменную-член в действии или фрагменте.

  2. Вызывайте startActionMode(), когда хотите показать панель, например когда пользователь нажимает и удерживает объект 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.

Как создать всплывающее меню

Изображение, на котором показано всплывающее меню в приложении Gmail, привязанное к кнопке &quot;Ещё&quot; в правом верхнем углу.
Рисунок 4. Всплывающее меню в приложении Gmail, привязанное к кнопке "Ещё" в правом верхнем углу.

PopupMenu – это модальное меню, привязанное к View. Оно появляется под закрепленным представлением, если там есть место, или над ним. Это полезно в следующих случаях:

  • Предоставление меню в стиле переполнения для действий, связанных с определенным контентом, например заголовками сообщений электронной почты Gmail, как показано на рисунке 4.
  • Дополнение команды. Например, кнопка Добавить, при нажатии на которую открывается всплывающее меню с разными вариантами добавления.
  • Предоставление меню, похожего на Spinner, которое не сохраняет постоянный выбор.

Если вы определяете меню в XML, вот как можно показать всплывающее меню:

  1. Создайте экземпляр PopupMenu с помощью конструктора, который принимает текущее приложение 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() в вашем интерфейсе.

Это показано в следующем примере:

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().

Когда пользователь выбирает элемент, система вызывает соответствующий метод обратного вызова, например 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, будь то операция в вашем или другом приложении. Если вы знаете, какой объект Intent хотите использовать, и у вас есть определенный пункт меню, который его инициирует, вы можете выполнить объект Intent с помощью метода startActivity() во время соответствующего метода обратного вызова on-item-selected, например обратного вызова onOptionsItemSelected().

Однако если вы не уверены, что на устройстве пользователя есть приложение, которое обрабатывает намерение, то добавление пункта меню, который его вызывает, может привести к неработающему пункту меню, поскольку намерение может не разрешиться в действие. Чтобы решить эту проблему, 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;
}

Для каждого действия, которое предоставляет фильтр интентов, соответствующий заданному интенту, добавляется пункт меню. В качестве названия пункта используется значение 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>

Подробнее о том, как создавать фильтры интентов, рассказывается в статье Интенты и фильтры интентов.