Wednesday, March 24, 2010

Android Options menu: Internals (eng)

Android applications (Activities) can have own menus next types:
  • Options menu - the main menu of application, is displayed when user clicks Menu button
  • Сontext menu - the context menu, is shown when user makes long click on some control
Сontext menu looks like a simple List view dialog and there is a possibility to change its view by using Android themes. I have been investigated an ability to manage the Options menu view and would like to share results in this post.


A typical Android menu looks like next:
It can have icon and caption, it is possible to use sub-menus that looks like the Android Context menu.
There are some constraints for menus:
  • There is displayed not more than 6 menu items меню, three per row. If menu items are more than 6 they are collected into the "More" sub-menu.
  • There are supported only a one level sub-menus, so it is not possible to create a sub-menu for sub-menu item..

 Implementation
Options menu is realized by Android Menu class which object is passed into Activity.onCreateOptionsMenu() that is called at once, when Application creates menu.

This interface allow to work only with menu structure and does not provide methods to manage menu view. But it would like to set menu background, items count per row, menu sizes, - in general, make menu more attractive.

Internal classes
Android draws menu by using the com.android.internal.view.menu package that contains next interesting classes:
  • IconMenuView - menu view class
  • IconMenuItemView - menu item view class
  • MenuBuilder - implements the Menu interface and creates (builds) IconMenuView
  • MenuItemImpl - implements the MenuItem interface and creates a view for it
We are interested by only IconMenuView class which creates view for Android menu.

IconMenuView
The IconMenuView class has next properties:
  • rowHeight - the height of a single menu row
  • maxRows - the maximum quantity of menu rows
  • maxItemsPerRow - the maximum quantity of menu items per row
  • maxItems - the maximum quantity of visible menu items
  • moreIcon - icon for grouped hidden menu items
 Next properties are delivered from MenuView:
  • horizontalDivider - horizontal divider (drawable)
  • verticalDivider - vertical divider (drawable)
  • itemBackground - menu background (drawable)
  • windowAnimationStyle - animation style
All of them are defined in <Android SDK folder>/data/res/values/attrs.xml, and their identifiers are defined in <Android SDK folder>/res/values/public.xml.

 Next is an example of menu definition (<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" />

Managing menu view
As you can see, the is an ability to tune the Android menu. But not all so simple...
The problem is that com.android.internal.*  are the internal system packages and it is not convenient to use them because they can be modified at any time by Android team. For example, there is described in Android docs that the PhoneWindow class (implements the Window interface) will be refactored in the future).

But I decided to look at next ways (each next of them was invented after the previous one had been failed):
  • Create a theme, set necessary properties and apply it for Activity. Unfortunately, there is no way to use IconMenuView properties in theme definition
  • Set properties directly to IconMenuView class. In general, it is possible to set some properties, for example background, for each menu item by using standard Android interfaces, but not more - the IconMenuView class does not have set- methods, so it is not possible to set any defined above properties
  • Redefine menu settings in resources. Unfortunately, it is not possible to edit resources on run-time
  • "Hack" resources - implement own resources/themes/etc classes. Unfortunately, all necessary Android methods and classes are final.
Conclusion
Unfortunately, it is impossible to change standard menu settings. All defined above properties can be used only by internal classes, so only Android team is able to use them.

So, there is only a one solution - create own Options menu and show it when used clicks on Menu button, and hide system menu.

4 comments:

  1. could you tell me how to hide system menu?

    ReplyDelete
  2. Sorry, the latest paragraph of this post means to hide the standard menu provided by Android.
    To do that just override Activity.onPrepareOptionsMenu() that should return false.

    ReplyDelete
  3. hey can u plz upload code for this..

    Thanks

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete