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

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

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

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

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

Меню опций и панель приложений
Меню параметров — это основной набор пунктов меню для действия. Здесь вы размещаете действия, оказывающие глобальное влияние на приложение, например «Поиск», «Написать электронное письмо» и «Настройки».

См. раздел «Создание меню параметров» .

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

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

См. раздел «Создание контекстного меню» .

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

См. раздел «Создание всплывающего меню» .

Определить меню в XML

Для всех типов меню Android предоставляет стандартный формат XML для определения пунктов меню. Вместо создания меню в коде действия определите меню и все его элементы в XML -ресурсе меню . Затем вы можете расширить ресурс меню, загрузив его как объект Menu , в своей активности или фрагменте.

Использование ресурса меню является хорошей практикой по следующим причинам:

  • Структуру меню проще визуализировать в XML.
  • Он отделяет содержимое меню от поведенческого кода вашего приложения.
  • Он позволяет создавать альтернативные конфигурации меню для разных версий платформы, размеров экрана и других конфигураций, используя структуру ресурсов приложения .

Чтобы определить меню, создайте XML-файл в каталоге res/menu/ вашего проекта и создайте меню со следующими элементами:

<menu>
Определяет Menu , которое является контейнером для пунктов меню. Элемент <menu> должен быть корневым узлом файла и может содержать один или несколько элементов <item> и <group> .
<item>
Создает MenuItem , представляющий один элемент меню. Этот элемент может содержать вложенный элемент <menu> для создания подменю.
<group>
Необязательный невидимый контейнер для элементов <item> . Он позволяет классифицировать элементы меню, чтобы они имели общие свойства, такие как активное состояние и видимость. Дополнительную информацию см. в разделе «Создание группы меню» .

Вот пример меню с именем game_menu.xml :

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/new_game"
          android:icon="@drawable/ic_new_game"
          android:title="@string/new_game"
          app:showAsAction="ifRoom"/>
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>

Элемент <item> поддерживает несколько атрибутов, которые можно использовать для определения внешнего вида и поведения элемента. Элементы предыдущего меню включают следующие атрибуты:

android:id
Идентификатор ресурса, уникальный для элемента, который позволяет приложению распознавать элемент, когда пользователь его выбирает.
android:icon
Ссылка на объект, который можно использовать в качестве значка элемента.
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 Таблиц.
Рис. 2. Приложение Google Таблицы с несколькими кнопками, включая кнопку переполнения действий.

Вы можете объявить элементы для меню параметров из своего подкласса Activity или подкласса Fragment . Если и ваша активность, и ваши фрагменты объявляют элементы для меню параметров, эти элементы объединяются в пользовательском интерфейсе. Сначала отображаются элементы действия, а затем элементы каждого фрагмента в том порядке, в котором фрагменты добавляются в действие. При необходимости вы можете изменить порядок пунктов меню с помощью атрибута android:orderInCategory в каждом <item> , который нужно переместить.

Чтобы указать меню параметров для действия, переопределите onCreateOptionsMenu() . Фрагменты предоставляют собственный обратный вызов onCreateOptionsMenu() . В этом методе вы можете добавить свой ресурс меню, определенный в XML , в Menu , предоставленное в обратном вызове. Это показано в следующем примере:

Котлин

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    val inflater: MenuInflater = menuInflater
    inflater.inflate(R.menu.game_menu, menu)
    return true
}

Ява

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

Вы также можете добавлять элементы меню с помощью add() и извлекать элементы с помощью findItem() чтобы изменить их свойства с помощью API MenuItem .

Обработка событий кликов

Когда пользователь выбирает элемент в меню параметров, включая элементы действий на панели приложения, система вызывает метод onOptionsItemSelected() вашего действия. Этот метод передает выбранный MenuItem . Вы можете идентифицировать элемент, вызвав метод getItemId() , который возвращает уникальный идентификатор элемента меню, определенный атрибутом android:id в ресурсе меню или целым числом, переданным методу add() . Вы можете сопоставить этот идентификатор с известными пунктами меню, чтобы выполнить соответствующее действие.

Котлин

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

Ява

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection.
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

Когда вы успешно обработаете пункт меню, верните true . Если вы не обрабатываете элемент меню, вызовите реализацию суперкласса onOptionsItemSelected() . Реализация по умолчанию возвращает false.

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

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

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

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

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

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

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

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

Существует два способа предоставления контекстных действий:

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

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

Создайте плавающее контекстное меню

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

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

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

  2. Реализуйте метод onCreateContextMenu() в своем Activity или Fragment .

    Когда зарегистрированное представление получает событие касания и удержания, система вызывает ваш метод onCreateContextMenu() . Здесь вы определяете пункты меню, обычно путем расширения ресурса меню, как в следующем примере:

    Котлин

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

    Ява

        @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() , как показано в следующем примере. Когда пользователь выбирает пункт меню, система вызывает этот метод, чтобы вы могли выполнить соответствующее действие.

    Котлин

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

    Ява

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

    Котлин

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

    Ява

        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 для внесения различных изменений в CAB, например для изменения заголовка и подзаголовка с помощью setTitle() и setSubtitle() , что полезно для указания количества выбранных элементов.

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

  2. Вызовите startActionMode() когда вы хотите отобразить панель, например, когда пользователь касается и удерживает представление.

    Котлин

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

    Ява

        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.
  • Предоставление второй части командного предложения, например кнопки с пометкой «Добавить» , которая создает всплывающее меню с различными параметрами «Добавить» .
  • Предоставление меню, похожего на 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" />

Затем действие может отображать всплывающее меню следующим образом:

Котлин

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

Ява

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() в вашем интерфейсе.

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

Котлин

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

Ява

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() . Это показано в следующем примере:

Котлин

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

Ява

@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 ищет любые приложения, которые могут выполнить это намерение, и добавляет их в ваше меню.

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

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

Котлин

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
}

Ява

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

Подробнее о написании фильтров намерений читайте в разделе Намерения и фильтры намерений .