官术网_书友最值得收藏!

Modifying menus and menu items during runtime

Though it's been stated many times, it's considered the "best" programming practice to create UI in XML rather than in Java. There are still times when you may need to do it in code. This is especially true if you wanted a menu item to be visible (or enabled) based on some external criteria. Menus can also be included in resource folders, but there are times when you need code to perform the logic. One example might be if you wanted to offer an upload menu item only if the user is logged in to your app.

In this recipe, we will create and modify the menu only through code.

Getting ready

Create a new project in Android Studio and call it RuntimeMenu using the default Phone & Tablet option. Select the Empty Activity option when prompted to add an Activity. Since we will create and modify the menu completely in code, we will not need to create a res/menu directory.

How to do it...

To start, we will add string resources for our menu items and a button to toggle the menu visibility. Open the res/strings.xml file and follow these steps:

  1. Add the following two strings to the existing <resources> element:
    <string name="menu_download">Download</string>
    <string name="menu_settings">Settings</string>
  2. Add a button to activity_main.xml with onClick() set to toggleMenu as shown here:
    <Button
        android:id="@+id/buttonToggleMenu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Toggle Menu"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:onClick="toggleMenu"/>
  3. Open ActivityMain.java and add the following three lines of code just below the class declaration:
    private final int MENU_DOWNLOAD = 1;
    private final int MENU_SETTINGS = 2;
    private boolean showDownloadMenu = false;
  4. Add the following method for the button to call:
    public void toggleMenu(View view) {
        showDownloadMenu=!showDownloadMenu;
    }
  5. When the activity is first created, Android calls onCreateOptionsMenu() to create the menu. Here is the code to dynamically build the menu:
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(0, MENU_DOWNLOAD, 0, R.string.menu_download);
        menu.add(0, MENU_SETTINGS, 0, R.string.menu_settings);
        return true;
    }
  6. For best programming practice, don't use onCreateOptionsMenu() to update or change your menu; instead, use onPrepareOptionsMenu(). Here is the code to change the visibility of the Download menu item based on our flag:
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        MenuItem menuItem = menu.findItem(MENU_DOWNLOAD);
        menuItem.setVisible(showDownloadMenu);
        return true;
    }
  7. Though not technically required for this recipe, this onOptionsItemSelected() code shows how to respond to each menu item:
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_DOWNLOAD:
                Toast.makeText(this, R.string.menu_download, Toast.LENGTH_LONG).show();
                break;
            case MENU_SETTINGS:
                Toast.makeText(this, R.string.menu_settings, Toast.LENGTH_LONG).show();
                break;
            default:
                return super.onContextItemSelected(item);
        }
        return true;
    }
  8. Run the program on a device or emulator to see the menu changes.

How it works...

We created an override for onCreateOptionsMenu(), just like we did in the previous recipe, Creating an Options Menu. But instead of inflating an existing menu resource, we created the menu using the Menu.add() method. Since we want to modify the menu items later as well as respond to the menu item events, we have defined our own menu IDs and passed them to the add() method.

onOptionsItemSelected() is called for all the menu items, so we get the menu ID and use a switch statement based on the IDs we created. We return true if we are handling the menu event, otherwise we pass the event to the super class.

Changing the menu occurs in the onPrepareOptionsMenu() method. To simulate an external event, we created a button to toggle a Boolean flag. The visibility of the Download menu is determined by the flag. This is where you would want to create your custom code based on whatever criteria you set. Your flag could be set using the current player level or maybe when a new level is ready for release; you send a Push message, which enables the menu item.

There's more...

What if we wanted this Download option to be easily noticed to indicate whether it's available? We could tell Android we want the menu in the Action Bar by adding the following code to onPrepareOptionsMenu() (before the return statement):

menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

Now if you run the code, you will see the Download menu item in the Action Bar, but the behavior isn't correct.

Earlier, when we didn't have a menu item in the Action Bar, Android called onPrepareOptionsMenu() each time we opened the overflow menu so the visibility was always updated. To correct this behavior, add the following line of code to the toggleMenu() method called by the button:

invalidateOptionsMenu();

The invalidateOptionsMenu() call tells Android that our option menu is no longer valid, which then forces a call to onPrepareOptionsMenu() giving us the behavior we expect.

Note

Android considers the menu as always open if a menu item is displayed in the Action Bar.

主站蜘蛛池模板: 灵武市| 新田县| 连江县| 红安县| 天等县| 东阳市| 屯门区| 陵川县| 绥阳县| 密云县| 无为县| 枣庄市| 浏阳市| 惠水县| 望谟县| 新丰县| 万宁市| 罗山县| 郎溪县| 商都县| 买车| 屏东市| 台中市| 山西省| 沧州市| 右玉县| 共和县| 永宁县| 新乡县| 漳浦县| 延长县| 澄江县| 云安县| 宁晋县| 息烽县| 旅游| 咸丰县| 长沙市| 鲁山县| 手游| 山丹县|