- . Это позволяет достичь некоторых эффектов
Предположим, мы решили использовать меню для какой-нибудь игры. Создадим новый файл game_menu.xml
:
Мы создали меню с двумя пунктами. Каждый пункт включает в себя следующие атрибуты:
Android:id Идентификатор пункта меню, по которому приложение может распознать при выделении пункта меню пользователем
android:title Текст, который будет выводиться в меню
Существуют и другие атрибуты для элемента item
, например android:icon="@drawable/home"
позволит также вывести значок для пункта меню, а android:enabled="false"
позволяет сделать пункт меню недоступным.
Атрибут android:titleCondensed
применяется в том случае, если обычный заголовок слишком широкий и не «помещается» в выбранном элементе меню.
Атрибут android:orderInCategory
определяет порядок, в котором отображаются элементы меню MenuItems.
При создании меню мы указали на строковые ресурсы @string/new_game
и @string/help
. Необходимо добавить новые строки в файле strings.xml
:
Новая игра
Справка
Теперь нужно внести изменения в классе активности, в котором будет выводиться меню. Программа должна сконвертировать созданный нами ресурс меню в программный объект. Для этой цели существует специальный метод MenuInflater.inflate()
, который вызывается в специальном методе обратного вызова onCreateOptionsMenu()
. Данный метод и предназначен для вывода меню при нажатии кнопки MENU
на устройстве:
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.game_menu, menu);
return true;
}
После вставки кода среда разработки попросит импортировать недостающие пространства имен.
Import android.view.Menu;
import android.view.MenuInflater;
Метод onCreateOptionsMenu()
метод инициирует первое появление меню на экране и принимает в качестве параметра объект Menu (для старых устройств). Вы можете сохранить ссылку на меню и использовать ее в любом месте кода, пока метод onCreateOptionsMenu()
опять не будет вызван. Вам необходимо всегда использовать реализацию этого обработчика из родительского класса, потому как она при необходимости автоматически включает в меню дополнительные системные пункты. В новых устройствах метод вызывается при создании активности. Метод должен возвращать значение true
, чтобы меню было видимым на экране.
Запустив программу, нажмите кнопку MENU
на эмуляторе, чтобы увидеть созданное меню.
Метод getMenuInflater()
возвращает экземпляр класса MenuInflater
, который мы используем для чтения данных меню из XML.
Как видите, меню появляется в нижней части экрана. Всего можно одновременно вывести на экран шесть пунктов меню. Если пунктов больше, то будет выведено пять пунктов плюс шестой пункт More
, который позволит увидеть остальные пункты. Давайте проверим и добавим новые пункты меню.
Сначала добавим шесть пунктов.
Добавим еще один пункт к меню, чтобы их стало семь.
Выбор пунктов меню
Мы научились создавать меню. Но пока оно бесполезно, так как пункты меню никак не реагируют на наши нажатия. Для обработки нажатий пунктов меню служит метод onOptionsItemSelected()
. Метод распознает пункт, выбранный пользователем, через MenuItem
. Мы можем теперь определить выбранный пункт через вызов getItemId()
, который возвращает идентификатор пункта меню. Далее через оператор switch
нам остается определить нужные команды:
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
// Операции для выбранного пункта меню
switch (item.getItemId())
{
case R.id.new_game:
newGame();
return true;
case R.id.help:
showHelp();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void newGame()
{
edtext.setText("Выбран пункт Новая игра");
}
public void showHelp()
{
edtext.setText("Выбран пункт Справка");
}
Запустите приложение, вызовите меню и выберите первый или второй пункт меню. В текстовом поле должно появиться сообщение.
В приведенном примере getItemId()
запрашивает ID для выбранного пункта меню и начинает сравнивать через оператор выбора switch с идентификаторами, которые мы задали в XML-ресурсах. При обнаружении нужного идентификатора выполняется обработчик для заданного пункта меню. Если программа ничего не обнаружит, то выполняется оператор default
, который возвращает super class.
В Android 3.0 можно добавить атрибут android:onClick
в ресурсах меню, и вам уже не нужно использовать onOptionsItemSelected()
. При помощи android:onClick
вы можете указать нужный метод при выборе пункта меню.
// у атрибута пункта меню установлено значение android:onClick="onMenuClick"
public void onMenuClick(MenuItem item){
edtext.setText("Выбран пункт Накормить кота");
}
Программное создание меню
Рассмотрим программное создание меню для полноты картины. Нам понадобится определить несколько констант для пунктов меню:
// идентификаторы для пунктов меню
private static final int IDM_OPEN = 101;
private static final int IDM_SAVE = 102;
public boolean onCreateOptionsMenu(Menu menu)
{
// добавляем пункты меню
menu.add(Menu.NONE, IDM_OPEN, Menu.NONE, "Открыть");
menu.add(Menu.NONE, IDM_SAVE, Menu.NONE, "Сохранить");
}
У метода add()
есть четыре параметра:
- идентификатор группы - позволяет связывать пункт меню с группой других пунктов этого меню
- идентификатор пункта для обработчика события выбора пункта меню
- порядок расположения пункта в меню - позволяет определять позицию в меню. По умолчанию (Menu.NONE или 0) пункты идут в том порядке, как задано в коде
- заголовок - текст, который выводится в пункте меню. Можно использовать строковый ресурс
Метод возвращает объект MenuItem
, который можно использовать для установки дополнительных свойств, например, для установить значок, горячую клавишу и т.д.
Если вы хотите создать меню со значками, то воспользуйтесь методом setIcon()
Menu.add(Menu.NONE, IDM_OPEN, Menu.NONE, "Открыть")
.setIcon(R.drawable.icon_menu_open);
Напомним еще раз, что значки можно добавить только к шести пунктам меню (или к пяти, если пунктов больше шести).
Метод onCreateOptionsMenu
вызывается системой только один раз при создании меню. Если вам требуется обновить меню во время работы программы, то используйте метод обратного вызова onPrepareOptionsMenu()
.
При выборе пункта меню вызывается метод onOptionsItemSelected
, который передает объект MenuItem
- пункт меню, выбранный пользователем. При помощи метода getItemId
можно получить идентификатор выбранного пункта меню. После идентификации пункта меню можно написать код для обработки события выбора меню:
Public boolean onOptionsItemSelected(MenuItem item)
{
switсh (item.getItemId())
case IDM_OPEN:
return true;
case IDM_SAVE:
return true;
return false;
}
Горячие клавиши
Также можно задавать горячие клавиши для быстрого доступа, используя символы клавиатуры, при помощи нескольких методов:
- setAlphabeticShortcut(char) - добавляет символ
- setNumericShortcut(int) - добавляет число
- setShortcut(char, int) - добавляет комбинацию символа и числа
Например, если задать горячую клавишу setAlphabeticShortcut("q");, то при открытии меню (или при удерживании клавиши MENU) нажатие клавиши Q
выберет данный пункт меню. Эта горячая клавиша (или сочетание клавиш) будет показана как подсказка, отображающая ниже имени пункта меню. В новых клавиатурах есть отдельная клавиша Ctrl
, которая работает также, как на обычных клавиатурах.
Горячие клавиши можно создать и через XML: android:alphabeticShortcut="c"
.
Обрабатывать нажатия можно через метод активности onKeyShortcut()
:
@Override
public boolean onKeyShortcut(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_R:
Toast.makeText(this, "Reply", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onKeyShortcut(keyCode, event);
}
}
Создание подменю
Подменю можно добавить в любое меню, кроме другого подменю. Подменю создается в методе обратного вызова onCreateOptionsMenu()
с помощью метода addSubMenu()
, который возвращает объект SubMenu
. В объект SubMenu
можно добавить дополнительные пункты к этому меню, используя метод add()
. Например:
Public static final int IDM_HELP = 101;
public static final int IDM_NEW = 201;
public static final int IDM_OPEN = 202;
public static final int IDM_SAVE = 203;
public static final int IDM_CUT = 301;
public static final int IDM_COPY = 302;
public static final int IDM_PASTE = 303;
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
SubMenu subMenuFile = menu.addSubMenu("Файл");
subMenuFile.add(Menu.NONE, IDM_NEW, Menu.NONE, "Новый");
subMenuFile.add(Menu.NONE, IDM_OPEN, Menu.NONE, "Открыть");
subMenuFile.add(Menu.NONE, IDM_SAVE, Menu.NONE, "Сохранить");
SubMenu subMenuEdit = menu.addSubMenu("Правка");
subMenuEdit.add(Menu.NONE, IDM_CUT, Menu.NONE, "Вырезать");
subMenuEdit.add(Menu.NONE, IDM_COPY, Menu.NONE, "Копировать");
subMenuEdit.add(Menu.NONE, IDM_PASTE, Menu.NONE, "Вставить");
menu.add(Menu.NONE, IDM_HELP, Menu.NONE, "Справка");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
CharSequence message;
switch (item.getItemId()) {
case IDM_NEW:
message = "Выбран пункт Новый";
break;
case IDM_OPEN:
message = "Выбран пункт Открыть";
break;
case IDM_SAVE:
message = "Выбран пункт Сохранить";
break;
case IDM_CUT:
message = "Выбран пункт Вырезать";
break;
case IDM_COPY:
message = "Выбран пункт Копировать";
break;
case IDM_PASTE:
message = "Выбран пункт Вставить";
break;
case IDM_HELP:
message = "Выбран пункт Справка";
break;
default:
return false;
}
// выводим уведомление о выбранном пункте меню
Toast toast = Toast.makeText(this, message, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
return true;
}
Теперь при выборе пункта меню появится еще одно окно с подменю. Попробуйте сами.
Добавление флажков и переключателей
В пункты меню возможно добавление флажков или переключателей. Чтобы добавить флажок или переключатель для отдельного элемента меню, необходимо
использовать метод setCheckable()
:
MenuItem item = menu.add(0, IDM_FORMAT_BOLD, 0, "Bold");
item.setCheckable(true);
Если есть необходимость добавить несколько пунктов меню с флажками или переключателями, то можно объединить их в группы меню, создав отдельный идентификатор. Пункт меню добавляется в группу через метод add()
, передав ему в качестве первого параметра идентификатор группы меню. Допустим, мы объявили идентификаторы для группы меню Цвет и элементов меню для установки цвета:
Public static final int IDM_COLOR_GROUP = 400;
public static final int IDM_COLOR_RED = 401;
public static final int IDM_COLOR_GREEN = 402;
public static final int IDM_COLOR_BLUE = 403;
Теперь для создания группы меню с флажками нужно назначить идентификатор группы на каждый пункт меню и вызвать метод setGroupCheckable()
для всей группы (этом случае нет необходимости вызывать метод setCheckable()
для каждого пункта меню):
SubMenu subMenuColor = menu.addSubMenu("Цвет");
subMenuColor.add(IDM_COLOR_GROUP, IDM_COLOR_RED, Menu.NONE, "Красный");
subMenuColor.add(IDM_COLOR_GROUP, IDM_COLOR_GREEN, Menu.NONE,"Зеленый");
subMenuColor.add(IDM_COLOR_GROUP, IDM_COLOR_BLUE, Menu.NONE, "Синий");
subMenuColor.setGroupCheckable(IDM_COLOR_GROUP, true, false);
У метода setGroupCheckable()
три параметра:
- первый параметр - идентификатор группы меню;
- второй параметр - true, если в группе разрешены переключатели или флажки;
- третий параметр - устанавливает единственный (true) или множественный (false) выбор пунктов меню. Этот параметр фактически определяет внешний вид
меню - это будет меню с переключателями или флажками.
Для управления состоянием флажков и переключателей в обработчике события выбора пункта меню нужно написать следующее:
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
CharSequence message;
switch (item.getItemId()) {
...
case IDM_COLOR_RED:
// инвертируем состояние флажка
item.setChecked(!item.isChecked());
message = "Красный цвет";
break;
default:
return false;
}
Запустите проект, вызовите меню и выберите пункт меню Цвет
. У вас появится подменю с тремя пунктами (Красный, Зеленый, Синий) в виде флажков. Состояние флажков и переключателей обрабатывается в коде программы и сохраняется при повторных вызовах меню.
Можно сразу назначить намерение выбранному пункту меню через метод setIntent(), которое сработает при нажатии этого пункта, если данное событие не было перехвачено обработчиками onMenuItemClickListener (устар.) или onOptionsItemSelected. Сработав, намерение передается в метод startActivity.
MenuItem.setIntent(new Intent(this, MyOtherActivity.class));
Программное открытие или закрытие меню
Если вам по каким-то причинам нужно программно открыть меню (например, в демонстрационных целях), то используйте метод openOptionsMenu()
:
OpenOptionsMenu();
Для программного закрытия меню используйте метод closeOptionsMenu()
, впрочем у меня повторный вызов метода openOptionsMenu()
также закрывает меню.
Программное удаление пункта меню
Допустим, мы определили пункт меню в xml-файле:
Чтобы удалить явно лишний пункт меню из нашей программы о котах, нужно получить доступ к пункту меню через метод findItem()
и сделать его невидимым. Ссылку на объект Menu нужно передать в метод onCreateOptionsMenu
, чтобы программа узнала об изменении состава меню.
// переменная класса
Menu menu;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// передаём ссылку на наш объект
this.menu = menu;
getMenuInflater().inflate(R.menu.test, menu);
return true;
}
// щелчок кнопки
public void onClick(View v) {
if (menu != null) {
// находим нужный элемент
MenuItem item_dog = menu.findItem(R.id.action_dog);
// делаем его невидимым
item_dog.setVisible(false);
}
}
Но у данного решения есть недостаток, если мы повернём экран, то активность пересоздатся и удалённое меню снова появится. Как же нам избавиться от сранного пёсика?
Надо запомнить состояние пункта меню и сохранить его в объекте типа Bundle в методе onSaveInstanceState
, а в методе onCreate()
извлечь сохранённое состояние и передать методу onPrepareOptionsMenu
, который вызывается перед показом меню на экране:
Package ru.alexanderklimov.test;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class TestActivity extends Activity {
Menu menu;
Boolean savedMenuDogIsVisible;
final static String KEY_MENU_DOG = "KEY_MENU_DOG";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
// извлекаем данные о видимости пункта меню
if (savedInstanceState != null) {
savedMenuDogIsVisible = savedInstanceState.getBoolean(KEY_MENU_DOG,
true);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
this.menu = menu;
getMenuInflater().inflate(R.menu.test, menu);
return true;
}
public void onClick(View v) {
if (menu != null) {
MenuItem item_dog = menu.findItem(R.id.action_dog);
// прячем пункт меню
item_dog.setVisible(false);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
if (menu != null) {
MenuItem item_dog = menu.findItem(R.id.action_dog);
// сохраняем текущее состояние пункта меню - true или false
outState.putBoolean(KEY_MENU_DOG, item_dog.isVisible());
}
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (savedMenuDogIsVisible != null) {
MenuItem item_dog = menu.findItem(R.id.action_dog);
// перед выводом на экран узнаём нужное состоятние пункта меню
item_dog.setVisible(savedMenuDogIsVisible);
}
return super.onPrepareOptionsMenu(menu);
}
}
Определить наличие кнопки Menu
На старых устройствах использовалась реальная кнопка Menu. В новых версиях Android меню убрали в ActionBar и её наличие в виде отдельной кнопки стало необязательным. Но многие производители по-прежнему выпускают телефоны с кнопкой для меню. Чтобы определить, есть ли такая кнопка, в Android 14 добавили новый метод, который позволит определить наличие этой кнопки.
If (Build.VERSION.SDK_INT <= 10
|| (Build.VERSION.SDK_INT >= 14 && ViewConfiguration.get(this)
.hasPermanentMenuKey())) {
// menu key is present
Toast.makeText(this, "Кнопка Menu есть", Toast.LENGTH_LONG).show();
} else {
// No menu key
Toast.makeText(this, "Кнопки Menu нет", Toast.LENGTH_LONG).show();
}
Разметка для меню
В современных устройствах меню является частью ActionBar
. И вы можете настроить разметку меню через XML.
Допустим, вы выбрали такой вариант:
В атрибуте showAsAction
не используйте значение never
, иначе разметку не увидите. Сама разметка задана через атрибут actionLayout
. Код для разметки:
Меню в фрагментах
Меню может быть не только частью активности, но и частью фрагмента. Принцип работы практически не отличается. У фрагмента есть соответствующий метод.
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_crime_list, menu);
}
FragmentManager
отвечает за вызов onCreateOptionsMenu()
при получении активностью обратного вызова onCreateOptionsMenu()
от системы. Вы должны явно сообщить менеджеру FragmentManager
, что фрагмент должен получить вызов onCreateOptionsMenu()
. Для этого вызывается метод setHasOptionsMenu()
:
// В коде фрагмента
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
getActivity().setTitle(R.string.cat);
...
}
Когда то давно, лет 5 назад стремительно набирали популярность аппараты с операционной системой Android. Хорошее было время, мир выходил из кризиса, впереди было много интересного и на каждом аппарате была кнопка Меню.
Спустя 2 года парни из Android сообщили о том, что кнопка "меню" на корпусе аппарата теперь уже не модно и можно без неё. С тех пор каждый из нас (Гильдии разработчиков) знает, как вызвать меню на подавляющем большинстве андроид девайсов.
Кому то это покажется страшным баяном, пусть так, но на прошлой неделе мы потратили 2 часа своей жизни на то, чтобы это объяснить пользователю. Мириться с этим было нельзя, поэтому ниже привожу описание того, как вызвать функцию меню на андроид аппаратах.
Вот так выглядят механические кнопки меню на большинстве распространённых устройств:
Причём в большинстве случаев для вызова функции меню достаточно одного короткого касания.
Однако, часто вызов меню может быть добавлен к кнопке выбора запущенных приложений. Выглядит она так:
В этом случае меню откроется только при долгом нажатии
(так называемый лонг-клик)! То есть не просто ткнули пальцем, а ткнули и подержали
. Многие говорят после этого Вау!
Владельцам планшетов советую обратить внимание на рабочую область экрана, именно там чаще всего находятся кнопки, в том числе и Меню.
Причём не всегда максимально справа, но выглядит эта кнопка именно так.
На свежих версиях Android OS кнопка меню выглядит так.
Создание меню
Последнее обновление: 26.02.2017
Меню в приложениях представляет класс android.view.Menu
, и каждая activity ассоциируется с объектом этого типа.
Объект android.view.Menu может включать различное количество элементов, а те в свою очередь могут хранить подэлементы.
Определение меню в xml
Меню, как и файлы интерфейса или изображений, также представляет собой ресурс. По умолчанию файлы меню находятся в проекте в каталоге
res/menu
.
При создании нового проекта с Empty Activity у нас нет никакого каталога res/menu и соответственно нет ресурсов меню, но мы можем их добавить вручную.
Для этого нажмем правой кнопкой мыши в проекте на каталог res и далее в открывшемся списоке выберем пункт New -> Android Resource File
:
После этого в каталоге res будет создан подкаталог menu, в котором будет находиться файл main_menu.xml.
По умолчанию этот файл определяет один пустой элемент menu:
Изменим содержимое файла, определив несколько пунктов:
Тег