Android App Development: Menus part 1: Options menu

By
On March 2, 2011

In today’s Android App Development tutorial we are going to go over the options menu.

Android phones have the menu button which displays a menu with several items that provide navigation or more functionality or settings to your applications.

Android has three types of menus

  1. Options menu.
  2. Context menu.
  3. Alternative menus.

Menu items can be grouped and each menu item can have submenu items.

Options Menu:

Each activity has a single menu. It appears when you press the menu button Each activity creates this menu in the callback method onCreateOptionsMenu you can override this method and add items to the menu.

If you press the menu button you will see the menu like this:

public class MenusDemo extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
     menu.add("Item1");
     menu.add("Item2");
     return true;
    }
}

Notice that the onCreateOptionsMenu method returns a Boolean. It should return true for the menu to appear, if returns false the menu will be invisible.

If you add many menu items, more than five items they will appear like this:

public boolean onCreateOptionsMenu(Menu menu)
    {
     menu.add(1, 1, 0, "Item1");
     menu.add(1, 2, 1, "Item2");
     menu.add(1, 3, 2, "Item3");
     menu.add(1, 4, 3, "Item4");
     menu.add(1, 5, 4, "Item5");

     menu.add(2, 6, 0, "Item6");
     menu.add(2, 7, 1, "Item7");
     menu.add(2, 8, 2, "Item8");
     menu.add(2, 9, 3, "Item9");
     menu.add(2, 10, 4, "Item10");

     return true;
    }

When you press on the “more” link you will see the rest of the menu items:

The menu.add(int GroupID,int ItemID,int Order,String Title) method has the following parameters:

  1. GroupID: used to group related menu items to apply some configurations on all items of a certain group once at a time (discussed later) .
  2. ItemID: an integer to identify the menu item.
  3. Order: the sort order or the order ID, controls the order of menu items in a menu. Items with lower order id appear first. There are some constants defined for sort order for different kinds of menu items
    Like Menu.CATEGORY_SECONDRY for secondry menu items, Menu.CATEGORY_SYSTEM for system menu items and Menu.CATEGORY_ALTERNATIVE for altenative menu items..
  4. Title: the text of the menu item

We could have written the previous code using the predefined the sort order constants like this:

menu.add(1, 1, Menu.FIRST, "Item1");
     menu.add(1, 2, Menu.FIRST+1, "Item2");
     menu.add(1, 3, Menu.FIRST+2, "Item3");
     menu.add(1, 4, Menu.FIRST+3, "Item4");
     menu.add(1, 5, Menu.FIRST+4, "Item5");

     menu.add(2, 6, Menu.CATEGORY_SECONDARY, "Item1");
     menu.add(2, 7, Menu.CATEGORY_SECONDARY+1, "Item2");
     menu.add(2, 8, Menu.CATEGORY_SECONDARY+2, "Item3");
     menu.add(2, 9, Menu.CATEGORY_SECONDARY+3, "Item4");
     menu.add(2, 10, Menu.CATEGORY_SECONDARY+4, "Item5");

Adding Icons to menu items:

We saw that only the first five items can appear in the options menu and the other items appear in a dialog when you press “more” item.

For the first five items you can add an icon to appear next to the item’s title:

menu.add(1, 1, 0, "Blu-Ray").setIcon(R.drawable.bluray);
     menu.add(1, 2, 1, "DVD").setIcon(R.drawable.dvd);
     menu.add(1, 3, 2, "Hard Disk").setIcon(R.drawable.hd);
     menu.add(1, 4, 3, "Sites").setIcon(R.drawable.sites);
     menu.add(1, 5, 4, "USB").setIcon(R.drawable.usb);

     menu.add(2, 6, 5, "Item1");
     menu.add(2, 7, 6, "Item2");
     menu.add(2, 8, 7, "Item3");
     menu.add(2, 9, 8, "Item4");
     menu.add(2, 10, 9, "Item5");

Grouping Menu Items:

We saw that the method we use to add menu items us Menu.Add(GroupID,ItemId,OrderID,Title).

The first parameter is GroupID, what is it ? the answer leads us to grouping Menu Items.

Grouping menu items makes it easy to apply some options on some related menu items by applying these options on all menu items that belong to a group once instead of applying them on each single item at a time.

The actions that can be applied on a group can be:

  • Menu.removeGroup(int GroupID): to remove all menu items belonging to the same group.
  • Menu.setGroupCheckable(int GroupID,Boolean Checakble,Boolean Exclusive): maked a group appear with a check mark beside each item. If the Boolean Exclusive is set to true then the items will appear as if they are in a radiobuttongroup and only one item can be selected at a time. If set to false then they will appear with check boxes beside each item and multiple items can be selected at a time.
  • Menu.setGroupEnabled(int GroupID,Boolean Enabled): sets all items in a group to be enabled/disabled.
  • Menu.setGroupVisible(int GroupID,Boolean Visible): sets all items in a group to be visible/invisible.

Note: the methods mentioned above can be applied only to menu items in the secondary menu (items that appear when you click the more button).

Adding Alpha-Numeric shortcuts to menu Items:

You can add alphabetic or numeric shortcuts to menu items like this:

menu.add(2, 8, 7, "Item3").setNumericShortcut('3');
menu.add(2, 9, 8, "Item4").setAlphabeticShortcut('c');

then setting the querty mode of the menu to true like this:

menu.setQwertyMode(true);

Handling Menu Items Events:

We can handle menu items events by three ways:

  1. By implementing onOptionsItemSelected method.
  2. By implementing listeners to single menu items.
  3. By using intents.

Using onOptionsItemSelected method:

Implement the onOptionsItemSelected method like this:

@Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
     TextView txt=(TextView)findViewById(R.id.txt);
     switch(item.getItemId())
     {
     case 1:
      txt.setText("you clicked on item "+item.getTitle());
      return true;
     case 2:
      txt.setText("you clicked on item "+item.getTitle());
      return true;
     case 3:
      txt.setText("you clicked on item "+item.getTitle());
      return true;

     }
     return super.onOptionsItemSelected(item);

    }

Notice that we return true for every handled menu item. And for un handled menu items (outside switch block) we call the super class method.

Using listners:

We can handle options menu items click events by making the activity implement onMenuItemClickListner interface provide an implementation of onMenuItemClick method like this:

public class MenusDemo extends Activity implements OnMenuItemClickListener

Then implement the method:

public boolean onMenuItemClick(MenuItem item) {
  TextView txt=(TextView)findViewById(R.id.txt);
  txt.append("listner");
  return false;
 }

Notice that the method returns a Boolean. If it returns true no other callbacks will be executed. If returns false then onOptionsItemSelected callback will be executed directly after this callback.

Using intents:

You can specify an intent to be launched when an options menu item is clicked like this:

menu.add(1, “dialItem”, 1, "Dial").setIcon(R.drawable.dvd).setIntent(new Intent(Intent.ACTION_DIAL));

Note that if you specify an intent for an item and at the same time override the onOptionsItemSelected method and handle the selection for that item, the precedence of execution is to the code in the onOptionsItemSelected.

Meaning that the code in onOptionsItemSelected method will be executed first, if it returns true then the intent will not be launched, if returns false then the intent will launch.

So if you want to use intent for menu items don’t handle it in onOptionsItemSelected method but invoke the parent onOptionsItemSelected.

Scenario 1:

@Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
     menu.add(1, “dialItem”, 1, "Dial").setIcon(R.drawable.dvd).setIntent(new Intent(Intent.ACTION_DIAL));     return super.onCreateOptionsMenu(menu);

    }

@Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
     TextView txt=(TextView)findViewById(R.id.txt);
     switch(item.getItemId())
     {
     case 1:
      txt.append("you clicked on item "+item.getTitle());
      return true;
     case “dialItem”:
      txt.setText("you clicked on item "+item.getTitle());
      return true;
     case 3:
      txt.setText("you clicked on item "+item.getTitle());
      return true;

     }
     return super.onOptionsItemSelected(item);

    }

This will execute the code of the onOptionsItemSelected method and the dialer intent will not be launched.

Scenario 2:

@Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
     menu.add(1, “dialItem”, 1, "Dial").setIcon(R.drawable.dvd).setIntent(new Intent(Intent.ACTION_DIAL));
     return super.onCreateOptionsMenu(menu);

    }

@Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
     TextView txt=(TextView)findViewById(R.id.txt);
     switch(item.getItemId())
     {
     case 1:
      txt.append("you clicked on item "+item.getTitle());
      return true;
     case “dialItem”:
      txt.setText("you clicked on item "+item.getTitle());
      return false;
     case 3:
      txt.setText("you clicked on item "+item.getTitle());
      return true;

     }
     return super.onOptionsItemSelected(item);

    }
This will execute the code of  the onOptionsItemSelected method and then dialer intent will be launched.

Scenario 3:

@Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
     menu.add(1, “dialItem”, 1, "Dial").setIcon(R.drawable.dvd).setIntent(new Intent(Intent.ACTION_DIAL));     return super.onCreateOptionsMenu(menu);

    }

@Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
     TextView txt=(TextView)findViewById(R.id.txt);
     switch(item.getItemId())
     {
     case 1:
      txt.append("you clicked on item "+item.getTitle());
      return true;

     case 3:
      txt.setText("you clicked on item "+item.getTitle());
      return true;

     }
     return super.onOptionsItemSelected(item);

    }

the onOptionsItemSelected does not handle the “dialerItem” selection, so The dialer intent will be launched directly.

I hope you enjoyed this tutorial, if you have any questions please ask them in the comments.