page.title=Меню parent.title=Пользовательский интерфейс parent.link=index.html @jd:body
Меню являются стандартным компонентом пользовательского интерфейса в приложениях многих типов. Для обеспечения привычной и единообразной технологии работы с приложением следует представлять действия пользователя и другие варианты выбора в своих операциях с помощью API-интерфейсов класса {@link android.view.Menu}.
Начиная с версии Android 3.0 (уровень API 11) в устройствах, работающих под управлением Android, наличие отдельной кнопки Меню больше не требуется. С учетом этого изменения приложения для Android должны перестать зависеть от традиционной панели меню из 6 пунктов. Вместо нее в них должна быть строка действий с часто используемыми действиями пользователя.
Несмотря на то что оформление и поведение некоторых пунктов меню изменились, семантика для определения набора действий и вариантов по-прежнему основана на API-интерфейсах класса {@link android.view.Menu}. В этом руководстве рассказывается, как создавать три основополагающих типа меню или представлений действий в системе Android всех версий:
При разработке приложений для версии Android 2.3 или более ранних версий пользователи могут открыть панель меню параметров нажатием кнопки Меню.
В версии Android 3.0 и последующих версиях пункты меню параметров размещаются в строке действий в виде сочетания отображаемых на экране вариантов действий и раскрывающегося списка дополнительных вариантов выбора. Начиная с Android 3.0 кнопка Меню больше не используется (на некоторых устройствах ее нет), поэтому для предоставления доступа к действиям и другим вариантам выбора вам следует перейти к использованию строки действий.
См. раздел Создание меню параметров
При разработке приложения для версии Android 3.0 или выше вместо этого для обеспечения действий с выбранным контентом следует использовать режим контекстных действий. В этом режиме в строке, расположенной вверху экрана, отображаются пункты действий, затрагивающие выбранный контент, причем пользователь может выбрать сразу несколько элементов.
См. раздел Создание контекстного меню
См. раздел Создание всплывающего меню
Для определения пунктов меню всех типов в Android используется стандартный формат XML. Вместо того чтобы создавать меню в коде своей операции, определять меню и все его пункты следует в ресурсе меню формата XML. После этого ресурс меню можно будет загружать как объект {@link android.view.Menu} в свои операции или фрагменты.
Использовать ресурсы меню рекомендуется по нескольким причинам:
Чтобы определить меню, создайте файл XML в папке res/menu/
вашего проекта и постройте меню со следующими элементами:
<menu>
<menu>
должен быть корневым узлом файла, в котором может находиться один или несколько элементов
<item>
и <group>
.<item>
<menu>
для создания вложенных меню.<group>
Вот пример меню с именем 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" android:showAsAction="ifRoom"/> <item android:id="@+id/help" android:icon="@drawable/ic_help" android:title="@string/help" /> </menu>
Элемент <item>
поддерживает несколько атрибутов, с помощью которых можно определить внешний вид и
поведение пункта меню. Пункты приведенного выше меню имеют следующие атрибуты:
Это самые важные атрибуты, которые следует использовать, но есть также множество других атрибутов. Сведения обо всех поддерживаемых атрибутах см. в документе Ресурс меню.
К пункту любого меню (кроме вложенного меню) можно прикрепить вложенное меню, добавив элемент {@code <menu>} в качестве дочернего элемента {@code <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 в программируемый объект) с помощью метода {@link android.view.MenuInflater#inflate(int,Menu) MenuInflater.inflate()}. В приведенных далее разделах рассказывается, как загружать меню каждого типа.
Рисунок 1. Меню параметров в браузере на Android 2.3.
В меню параметров следует размещать действия и другие варианты выбора, которые имеют отношение к контексту текущей операции, например: "Поиск", "Составить сообщение эл. почты" и "Настройки".
Место, где отображаются на экране пункты вашего меню параметров, определяется версией платформы, для которой разработано приложение.
Подробные сведения о пунктах действий и других особенностях строки действий см. в руководстве Строка действий.
Примечание. Даже если ваше приложение не предназначено для работы в версии Android 3.0 или более поздней, можно создать собственный макет со строкой действий, чтобы реализовать похожий эффект. Пример того, как можно поддерживать работу строки действий в старых версиях Android см. в образце кода, иллюстрирующем Совместимость строки действий.
Рисунок 2. Строка действий из приложения Honeycomb Gallery, содержащая вкладки навигации и пункт включения камеры (а также кнопку открытия дополнительной панели действий).
Объявлять пункты меню параметров можно либо из подкласса {@link android.app.Activity}, либо из подкласса {@link android.app.Fragment}. Если и ваша операция, и фрагменты объявляют пункты меню параметров, в пользовательском интерфейсе они объединяются. Сначала отображаются пункты операции, а за ними следуют пункты фрагментов в том порядке, в котором каждый фрагмент добавляется в операцию. При необходимости можно изменить порядок следования пунктов меню с помощью атрибута {@code android:orderInCategory}, указываемого в каждом {@code <item>}, который требуется переместить.
Чтобы указать меню параметров для операции, переопределите {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (фрагменты предоставляют собственный обратный вызов {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}). В этом методе можно загрузить собственный ресурс меню (определенный в XML) в класс {@link android.view.Menu}, имеющийся в обратном вызове. Например:
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = {@link android.app.Activity#getMenuInflater()}; inflater.inflate(R.menu.game_menu, menu); return true; }
Пункты меню также можно добавлять с помощью {@link android.view.Menu#add(int,int,int,int) add()}, а получать их с помощью {@link android.view.Menu#findItem findItem()} для пересмотра их свойств с помощью API-интерфейсов {@link android.view.MenuItem}.
Если ваше приложение предназначено для версии Android 2.3.x или более ранней, система вызывает метод {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} для создания меню параметров, когда пользователь открывает это меню впервые. Если приложение предназначено для версии Android 3.0 и или более поздней, система вызывает метод{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} при запуске операции, чтобы отобразить пункты в строке действий.
Когда пользователь выбирает пункт меню параметров (в том числе пункты действий из строки действий), система вызывает метод {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} вашей операции. Этот метод передает выбранный класс {@link android.view.MenuItem}. Идентифицировать пункт меню можно, вызвав метод {@link android.view.MenuItem#getItemId()}, который возвращает уникальный идентификатор пункта меню (определенный атрибутом {@code android:id} из ресурса меню или целым числом, переданным методу {@link android.view.Menu#add(int,int,int,int) add()}). Этот идентификатор можно сопоставить с известными пунктами меню, чтобы выполнить соответствующее действие. Например:
@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); } }
Когда пункт меню успешно обработан, возвращается {@code true}. Если пункт меню не обрабатывается, следует вызвать реализацию суперкласса {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} (реализация по умолчанию возвращает значение false).
Если в вашей операции имеются фрагменты, система сначала вызовет метод {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} для операции, а затем будет вызывать этот метод для каждого фрагмента (в том порядке, в котором они были добавлены), пока он не возвратит значение{@code true} или не закончатся фрагменты.
Совет. В Android 3.0 появилась возможность определять в XML поведение при нажатии для пунктов меню с помощью атрибута {@code android:onClick}. Значением этого атрибута должно быть имя метода, определенное операцией с помощью меню. Этот метод должен быть общедоступным и принимать один параметр {@link android.view.MenuItem}, — когда система вызывает этот метод, она передает ему выбранный пункт меню. Подробные сведения и пример см. в документе Ресурс меню.
Совет. Если в приложении предусмотрено несколько операций и в некоторых из них имеются одинаковые меню параметров, рассмотрите возможность создания операции, которая будет использовать исключительно методы {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} и {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}. Затем распространите этот класс на все операции, у которых должно быть одинаковое меню параметров. Таким образом можно управлять одним набором кода для обработки действий меню, а каждый класс-потомок при этом будет наследовать режимы работы меню. Если требуется добавить пункты меню в одну из операций-потомков, переопределите метод {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} в этой операции. Вызовите метод {@code super.onCreateOptionsMenu(menu)}, с тем чтобы создать первоначальные пункты меню, а затем добавьте новые пункты меню с помощью метода {@link android.view.Menu#add(int,int,int,int) menu.add()}. Также можно переопределять режимы работы суперкласса для отдельных пунктов меню.
После того как система вызовет метод {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}, она сохранит заполненный вами экземпляр {@link android.view.Menu} и будет вызывать метод {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} ,только если меню по каким-то причинам станет некорректным. Однако метод {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} следует использовать только для создания начального состояния меню, а не для внесения в него изменений в течение жизненного цикла операции.
Если вам требуется изменять меню параметров в зависимости от событий, которые возникают в течение жизненного цикла операции, сделать это можно в методе{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}. Этот метод передает объект {@link android.view.Menu} в том виде, в котором он в данный момент существует. Его-то и можно изменить путем, например, добавления, удаления или отключения пунктов меню. (Фрагменты также предоставляют обратный вызов {@link android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()}.)
В версии Android 2.3.x или более ранней система вызывает метод {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} каждый раз, когда пользователь открывает меню параметров (нажимает кнопку Меню ).
В версии Android 3.0 и последующих версиях считается, что меню параметров всегда открыто, когда пункты меню приведены в строке действий. Когда возникает событие и требуется обновить меню, следует вызвать метод {@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()}, чтобы запросить у системы вызов метода {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}.
Примечание. Никогда не следует изменять пункты меню параметров с учетом класса {@link android.view.View}, действующего в данный момент. В сенсорном режиме (когда пользователь не использует трекбол или кнопки направления движения) фокус не может переводиться на представления, поэтому никогда не следует использовать фокус в качестве основы для изменения пунктов меню параметров. Если вы желаете предоставить пункты меню, которые зависят от контекста {@link android.view.View}, используйте контекстное меню.
Рисунок 3. Снимки экрана с плавающим контекстным меню (слева) и строкой контекстных действий (справа).
В контекстном меню содержатся действия, которые затрагивают определенный элемент или контекстный кадр в пользовательском интерфейсе. Контекстное меню можно создать для любого представления, но чаще всего они используются для элементов из {@link android.widget.ListView}, {@link android.widget.GridView} или других групп представлений, в которых пользователь может выполнять действия непосредственно с каждым элементом.
Существует два способа предоставления возможности контекстных действий:
Примечание. Режим контекстных действий поддерживается в версии Android 3.0 (уровень API 11) и последующих версиях. Если этот режим предусмотрен, именно его рекомендуется использовать для отображения контекстных действий. Если ваше приложение поддерживает версии ниже 3.0, то для этих устройств следует вернуться к плавающему контекстному меню.
Программирование плавающего контекстного меню
Если операция использует {@link android.widget.ListView} или {@link android.widget.GridView} и требуется, чтобы каждый элемент предоставлял одинаковое контекстное меню, зарегистрируйте все элементы для контекстного меню, передав {@link android.widget.ListView} или {@link android.widget.GridView} методу {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.
Когда зарегистрированное представление примет событие длительного нажатия, система вызовет ваш метод {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} . Именно здесь определяются пункты меню. Делается это обычно путем загрузки ресурса меню. Например:
@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); }
{@link android.view.MenuInflater} позволяет загружать контекстное меню из ресурса меню. В число параметров метода обратного вызова входят {@link android.view.View}, выбранный пользователем, и объект{@link android.view.ContextMenu.ContextMenuInfo}, который предоставляет дополнительную информацию о выбранном элементе. Если в вашей операции есть несколько представлений и все они предоставляют разные контекстные меню, то с помощью этих параметров можно определять, какое контекстное меню загружать.
Когда пользователь выбирает пункт меню, система вызывает этот метод, с тем чтобы вы могли выполнить соответствующее действие. Например:
@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); } }
Метод {@link android.view.MenuItem#getItemId()} запрашивает идентификатор для выбранного пункта меню. Идентификаторы должны быть назначены каждому пункту меню в файле XML с помощью атрибута {@code android:id}, как описано в разделе Определение меню в файле XML.
Когда пункт меню успешно обработан, возвращается {@code true}. Если пункт меню не обрабатывается, следует передать его реализации суперкласса. Если в вашей операции есть фрагменты, то она получит этот обратный вызов первой. Вызывая суперкласс, когда пункт меню не обрабатывается, система передает событие соответствующему методу обратного вызова в каждом фрагменте по одному (в порядке добавления каждого фрагмента), пока не будет возвращено значение {@code true} или {@code false}. (Реализация {@link android.app.Activity} и {@code android.app.Fragment} по умолчанию возвращает {@code false}, поэтому, когда событие не обрабатывается, следует всегда вызывать суперкласс.)
Режим контекстных действий представляет собой системную реализацию класса {@link android.view.ActionMode}, которая направляет пользователя на выполнение контекстных действий при взаимодействии с приложением. Когда пользователь использует этот режим, выбирая элемент, вверху экрана открывается строка контекстных действий, содержащая действия, которые пользователь может выполнить с выбранными в данный момент элементами. В этом режиме пользователь может выбирать несколько элементов (если это допускается приложением), снимать выделения с элементов и продолжать навигацию в операции (в тех пределах, в которых это поддерживается приложением). Режим контекстных действий отключается, а строка контекстных действий исчезает, когда пользователь снимет выделение со всех элементов, нажмет кнопку НАЗАД или выберет действие Готово, расположенное с левой стороны строки.
Примечание. Строка контекстных действий не обязательно бывает связана со строкой действий. Они работают независимо друг от друга, даже несмотря на то, что визуально строка контекстных действий занимает положение строки действий.
Если вы разрабатываете приложение для версии Android 3.0 (уровень API 11) или последующих версий, то обычно вместо плавающего контекстного меню вам следует использовать контекстные действия.
Для представлений, которые предоставляют возможность контекстные действия, обычно следует вызывать режим контекстных действий при возникновении одного из двух (или сразу обоих) событий:
То, каким образом ваше представление вызывает режим контекстных действий и определяет поведение каждого действия, зависит от вас. Есть два базовых варианта:
В следующих разделах описывается конфигурация, необходимая для каждого из этих вариантов.
Если вам требуется вызывать режим контекстных действий, только когда пользователь выбирает определенные представления, то вам следует:
Например:
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { // Called when the action mode is created; startActionMode() was 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, but // may 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) { mActionMode = null; } };
Обратите внимание, что эти обратные вызовы событий почти точно такие же, как и обратные вызовы для меню параметров. Отличаются они только тем, что каждый из них также передает объект {@link android.view.ActionMode}, связанный с событием. С помощью API-интерфейсов {@link android.view.ActionMode} можно вносить различные изменения в CAB, например, указывать другой заголовок и подзаголовок с помощью {@link android.view.ActionMode#setTitle setTitle()} и {@link android.view.ActionMode#setSubtitle setSubtitle()} (удобно для указания количества выбранных элементов).
Также обратите внимание, что приведенный выше образец кода задает для переменной {@code mActionMode} значение null, когда режим действия прекращает свое существование. Далее вы узнаете, каким образом он инициализируется и чем может быть полезно сохранение составной переменной в операции или фрагменте.
someView.setOnLongClickListener(new View.OnLongClickListener() { // Called when the user long-clicks on someView public boolean onLongClick(View view) { if (mActionMode != null) { return false; } // Start the CAB using the ActionMode.Callback defined above mActionMode = getActivity().startActionMode(mActionModeCallback); view.setSelected(true); return true; } });
При вызове метода {@link android.app.Activity#startActionMode startActionMode()} система возвращает созданный класс {@link android.view.ActionMode}. Сохранив его в составной переменной, вы сможете вносить изменения в строку контекстных действий в ответ на другие события. В приведенном выше образце кода {@link android.view.ActionMode} используется для того, чтобы экземпляр {@link android.view.ActionMode} не создавался повторно, если он уже активен. Достигается это путем проверки, имеет ли элемент значение null перед запуском режима действий.
Если при наличии набора элементов в {@link android.widget.ListView} или {@link android.widget.GridView} (либо другом расширении {@link android.widget.AbsListView}) требуется разрешить пользователям выполнять пакетные действия, следует:
Например:
ListView listView = getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { // Here you can do something when items are selected/de-selected, // such as update the title in the CAB } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // Respond to clicks on the actions in the CAB switch (item.getItemId()) { case R.id.menu_delete: deleteSelectedItems(); mode.finish(); // Action picked, so close the CAB return true; default: return false; } } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate the menu for the CAB MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.context, menu); return true; } @Override public void onDestroyActionMode(ActionMode mode) { // Here you can make any necessary updates to the activity when // the CAB is removed. By default, selected items are deselected/unchecked. } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // Here you can perform updates to the CAB due to // an {@link android.view.ActionMode#invalidate} request return false; } });
Готово. Теперь, когда пользователь выберет элемент с помощью длительного нажатия, система вызовет метод {@link android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()} и отобразит строку контекстных действий с указанными действиями. Пока строка контекстных действий отображается, пользователи могут выбирать дополнительные элементы.
В некоторых случаях, когда контекстные действия содержат общие пункты, можно добавить флажок или другой подобный элемент пользовательского интерфейса, с помощью которого пользователи могут выбирать пункты, поскольку они могут не обнаружить варианта с длительным нажатием. Когда пользователь устанавливает флажок, можно вызывать режим контекстных действий, переводя соответствующий элемент списка в выбранное состояние с помощью {@link android.widget.AbsListView#setItemChecked setItemChecked()}.
Рисунок 4. Всплывающее меню в приложении Gmail, привязанное к расположенной вверху справа кнопке открытия панели дополнительных пунктов.
{@link android.widget.PopupMenu} является модальным меню, привязанным к {@link android.view.View}. Оно отображается ниже представления, к которому привязано, если там есть место, либо поверх него. Варианты использования:
Примечание. Оно отличается от контекстного меню, которое обычно используется для действий, затрагивающих выбранный контент. Для действий, которые затрагивают выбранный контент, используйте режим контекстных действий или плавающее контекстное меню.
Примечание. Использование класса {@link android.widget.PopupMenu} поддерживается на уровне API 11 и выше.
Если для определения меню используется XML, вот каким образом можно показать всплывающее меню:
Например, вот кнопка с атрибутом {@link android.R.attr#onClick android:onClick}, которая показывает всплывающее меню:
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_overflow_holo_dark" android:contentDescription="@string/descr_overflow_button" android:onClick="showPopup" />
После этого операция сможет показать вот такое всплывающее меню:
public void showPopup(View v) { PopupMenu popup = new PopupMenu(this, v); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.actions, popup.getMenu()); popup.show(); }
На API уровня 14 и выше можно объединить две строки, которые загружают меню, с помощью {@link android.widget.PopupMenu#inflate PopupMenu.inflate()}.
Меню закрывается, когда пользователь выбирает один из пунктов или касается экрана за пределами области меню. Прослушивать событие закрытия меню можно с помощью {@link android.widget.PopupMenu.OnDismissListener}.
Для выполнения действия, когда пользователь выбирает пункт меню, необходимо реализовать интерфейс {@link android.widget.PopupMenu.OnMenuItemClickListener} и зарегистрировать его в своем {@link android.widget.PopupMenu}, вызвав метод {@link android.widget.PopupMenu#setOnMenuItemClickListener setOnMenuItemclickListener()}. Когда пользователь выбирает пункт меню, система выполняет обратный вызов {@link android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} в вашем интерфейсе.
Например:
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; } }
Группа меню ― это набор пунктов меню с рядом общих характеристик. С помощью группы можно:
Для создания группы необходимо вложить элементы {@code <item>} в элемент {@code <group>} в своем ресурсе меню либо указать идентификатор группы с помощью метода {@link android.view.Menu#add(int,int,int,int) 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>
Элементы, находящиеся в группе, отображаются на одном уровне с первым элементом — все три пункта меню являются элементами одного уровня. Однако можно изменить характеристики двух пунктов из группы, указав ссылку на идентификатор группы и воспользовавшись приведенными выше методами. Кроме того, система никогда не будет разделять сгруппированные пункты. Например, если объявить {@code android:showAsAction="ifRoom"} для каждого пункта, то они оба будут отображены либо в строке действий, либо в дополнительных действиях.
Рисунок 5. Снимок экрана с вложенным меню, пункты которого можно пометить.
Такое меню можно использовать в качестве интерфейса для включения и отключения тех или иных параметров. При этом для автономных параметров используется флажок, а для групп взаимоисключающих вариантов ― переключатель. На рисунке 5 показано вложенное меню с пунктами, которые можно выбирать с помощью переключателей.
Примечание. Пункты в меню значков (из меню параметров) не могут отображать флажки или переключатели. Если вы решите сделать так, чтобы пункты меню значков можно было помечать, вам необходимо будет вручную указать помеченное состояние путем замены значка и/или теста при каждом изменении состояния.
Определять возможность помечать отдельные пункты меню можно с помощью атрибута {@code android:checkable} в элементе {@code <item>}, а для всей группы это делается с помощью атрибута {@code android:checkableBehavior} в элементе {@code <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>
Атрибут {@code android:checkableBehavior} принимает один из трех параметров:
Для того чтобы применить к пункту помеченное состояние по умолчанию, служит атрибут {@code android:checked} в элементе {@code <item>}, а изменить его в коде можно с помощью метода {@link android.view.MenuItem#setChecked(boolean) setChecked()}.
Когда выбирается пункт, который может быть помечен, система вызывает соответствующий ему метод обратного вызова (например {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}). Именно здесь необходимо задать состояние флажка, поскольку флажок или переключатель не изменяет свое состояние автоматически. Запросить текущее состояние пункта (в котором он находился до того, как был выбран пользователем) можно с помощью{@link android.view.MenuItem#isChecked()}, а затем задать помеченное состояние с помощью {@link android.view.MenuItem#setChecked(boolean) setChecked()}. Например:
@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); } }
Если помеченное состояние не установить этим способом, то, когда пользователь выберет пункт, его отображаемое состояние (флажок или переключатель) не изменится. Если же помеченное состояние установить, операция сохранит его для пункта, с тем чтобы, когда пользователь откроет это меню, он увидел, что галочка поставлена.
Примечание. Пункты меню, которые можно пометить галочкой, предназначены для использования только в рамках одного сеанса. Они не сохраняются после прекращения существования приложения. Если имеются настройки приложения, которые требуется сохранить для пользователя, делать это следует с помощью общих настроек.
Иногда требуется, чтобы пункт меню запускал операцию с помощью объекта {@link android.content.Intent} (это может быть операция как из вашего, так и из другого приложения). Когда вам известен объект Intent, который требуется использовать, и у вас есть определенный пункт меню, который должен инициировать этот объект Intent, можно выполнить объект Intent с помощью {@link android.app.Activity#startActivity(Intent) startActivity()} во время выполнения соответствующего метода обратного вызова, запускаемого при выборе пункта меню (например, обратного вызова {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}).
Однако если вы не уверены, что на устройстве пользователя есть приложение, которое может обработать этот объект Intent, добавление пункта меню, который его вызывает, может привести к тому, что он не будет работать, поскольку объект Intent может не быть передан в операцию. Чтобы решить эту проблему, Android позволяет динамически добавлять в меню пункты, когда система Android обнаруживает на устройстве операции, которые могут обработать ваш объект Intent.
Добавление пунктов меню на основе имеющихся операций, которые принимают объект Intent:
При отсутствии установленных приложений, которые удовлетворяют требованиям объекта Intent, ни одного пункта меню добавлено не будет.
Примечание. {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} используется для обработки элемента, выбранного в данный момент на экране. Поэтому его следует использовать только при создании меню в {@link android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo) onCreateContextMenu()}.
Например:
@Override public boolean onCreateOptionsMenu(Menu menu){ super.onCreateOptionsMenu(menu); // Create an Intent that describes the requirements to fulfill, to be included // in our 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 applications. menu.addIntentOptions( R.id.intent_group, // Menu group to which new items will be 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 our requirements 0, // Additional flags to control items (none) null); // Array of MenuItems that correlate to specific items (none) return true; }
Каждая обнаруженная операция, в которой имеется фильтр Intent, соответствующий данному объекту Intent, добавляется в виде
пункта меню. Для этого значение из элемента android:label
фильтра Intent используется в качестве
заголовка пункта меню, а значок приложения ― в качестве значка этого пункта меню. Метод
{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
addIntentOptions()} возвращает количество добавленных пунктов меню.
Примечание. При вызове метода {@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) addIntentOptions()} он переопределяет все пункты меню по группе меню, указанной в первом аргументе.
Вы также можете предоставить другим приложениям возможность воспользоваться своей операцией, с тем чтобы ваше приложение могло быть включено в меню других приложений (процедура, обратная описанной выше).
Чтобы операция могла быть включена в меню других приложений, необходимо определить фильтр Intent обычным образом, но непременно включить в него значения {@link android.content.Intent#CATEGORY_ALTERNATIVE} и/или {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} для категории фильтра Intent. Например:
<intent-filter label="@string/resize_image"> ... <category android:name="android.intent.category.ALTERNATIVE" /> <category android:name="android.intent.category.SELECTED_ALTERNATIVE" /> ... </intent-filter>
Подробные сведения о написании фильтров Intent см. в документе Объекты Intent и фильтры объектов Intent.
Образец приложения, в котором используется эта методика, см. в образце кода Note Pad.