Wednesday, March 24, 2010

Android Options menu: Internals

Как и во всех платвормах, приложения (Activity) на Андроиде могут иметь свои собственные меню двух видов:
  • Options menu - главное меню программы, появляется при нажатии клавиши Menu.
  • Сontext menu - контекстное меню, появляется при длительном нажатии на каком-либо элементе управления.
Сontext menu представляет собой обычный List view диалог и есть возможность менять его вид, используя темы. Я исследовал возможность управление видом Options menu и хочу поделиться в этом посте полученными результатами.



Типичное меню Андроида выглядит так:
Меню может иметь иконку и надпись, также есть возможность использовать подменю, которые имеют тот же вид что и контекстные меню. Есть некоторые ограничения:
  • Андроид показывает максимум 6 элементов в меню, по 3 на строку. Если их больше, то они группируются в подменю More.
  • Подменю имеют только один уровень, то есть нельзя создать подменю у подменю.

Реализация
Options menu представляется в Андроиде интерфесом Menu, обьект которого передается в Activity.onCreateOptionsMenu() , который вызывается один раз, когда надо создать меню.

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


Внутренние классы
Система сама рисует меню, используя пакет com.android.internal.view.menu, который содержит следующие интересные классы:
  • IconMenuView - класс представления меню
  • IconMenuItemView - класс представления пункта меню
  • MenuBuilder - реализует интерфейс Menu и создает (строит) IconMenuView
  • MenuItemImpl - реализует интерфейс MenuItem (пункт меню) и создает его представление
В принципе, нам интересен только IconMenuView класс, который формирует вид меню.

IconMenuView
Клас IconMenuView имеет такие свойства:
  • rowHeight - высота одной строки меню
  • maxRows - максимальное количество строк
  • maxItemsPerRow - максимальное количество элементов на строку
  • maxItems - максимальное количество видимых элементов
  • moreIcon - иконка для сгруппированных элементов
 Следующие свойства унаследованы от MenuView:
  • horizontalDivider - горизонтальный разделитель (drawable)
  • verticalDivider - вертикальный разделитель (drawable)
  • itemBackground - задний фон меню (drawable)
  • windowAnimationStyle - стиль анимации
Все они описанные в файле <Android SDK folder>/data/res/values/attrs.xml, их идентификаторы - в <Android SDK folder>/res/values/public.xml.

 Вот пример описания меню (файл <Android SDK folder>/data/res/layout-land/icon_menu_layout.xml):
 <com.android.internal.view.menu.IconMenuView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+android:id/icon_menu"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:rowHeight="65dip"
    android:maxItems="6"
    android:maxRows="2"
    android:maxItemsPerRow="6" />

Настраивание меню
Как видно, предусмотрена возможность настраивать меню. Но не все так просто...
Беда в том, что com.android.internal.* - служебные пакеты, и использовать их не стоит, поскольку в любой момент могут быть изменены командой Андроида. Например в документации прямо написано, что класс PhoneWindow (реализует интерфейс Window) в дальнейшем будет отрефакторен.

И все же, я решил просмотреть такие варианты, каждый следующий из которых возникал при неудаче предыдущего:
  • Создать тему, задать необходимые параметры для меню, и применить ее к Activity. К сожаленью, нет возможности достучаться к свойствам IconMenuView в описании темы.
  • Задать параметры непосредственно IconMenuView. В принципе, можно задать некоторые свойства, например задний фон для каждого элемента меню, используя стандартные интерфейсы и классы Андроида, но не более - IconMenuView не имеет сеттеров, поэтому установить, например, максимальное количество строк не получиться
  • Переопределить параметры меню в ресурсах. К сожалению,нет возможности править ресурсы во время выполнения
  • "Хакнуть" ресурсы - реализовать свои классы ресурсов/тем/пр. Такой возможности тоже нет - либо все необходимые классы финальные, либо необходимые методы финальные.
Выводы
К сожаленью, как не крути, изменить стандартные свойства меню нельзя. Все перечисленные выше свойста могут использоваться только служебными классами, то есть что-то менять под силу только разработчикам из команды Андроида.

Поэтому здесь существует только одно решение - создать свое собственное меню и показывать его когда пользователь кликает на кнопку Меню, при этом надо прятать стандартное меню.

    No comments:

    Post a Comment