How can I alter a MenuItem on the Options Menu on Android?
Asked Answered
A

6

45

I have an Options Menu on my Activity with an MenuItem "Start". When this MenuItem is selected I would like to alter the Menu so it contains a MenuItem "Stop". And finally when "Stop" is selected, I would like to alter back to "Start".

Here is parts of my code that isn't working. I have both "Start" and "Stop" listed in mymenu.xml I should probably remove "stop" when the menu is created:

public class MyActivity extends Activity {
    private boolean isStarted = false;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        menu.removeItem(R.id.stop);
        inflater.inflate(R.menu.mymenu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.start:
            isStarted = true;
            return true;
        case R.id.stop:
            isStarted = false;
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if(isStarted) {
            menu.removeItem(R.id.start);
            menu.add(R.id.stop);
        } else {
            menu.removeItem(R.id.stop);
            menu.add(R.id.start);
        }
        return true;
    }
}
Algonquin answered 16/11, 2010 at 22:34 Comment(4)
Have you already tried to remove Stop when the menu is created? The code looks good. I can't spot anything which would cause issues other than that.Boatman
@Octavian: I tried with menu.removeItem(R.id.stop); after getMenuInflater(); but it didn't work. I either get two menu items, one "start" and one "false" (should be "stop"), or the menu crashes when I should be shown.Algonquin
where are you trying to call removeItem()? In onPrepareOptionsMenu()?Boatman
@Octavian: I remove the "stop" item in onCreateOptionsMenu() the first time, then I alter the items in onPrepareOptionsMenu(). I added this to the code in the question now.Algonquin
S
100

For this type of operation I usually choose not to alter the menu items, but just hide the ones you don't need:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    menu.findItem(R.id.start).setVisible(!isStarted);
    menu.findItem(R.id.stop).setVisible(isStarted);
    return true;
}
Series answered 11/2, 2011 at 16:1 Comment(2)
Just saw that I forgot to call the superclass as suggested earlier and specified in the docs and the sourceSeries
And just to update, the source can be found at grepcode.com/file/repository.grepcode.com/java/ext/…Series
T
21

Flygenring answer is correct, but menu.findItem() is laggy and calling it within onPrepareOptionsMenu(Menu menu) produces bad user experience. It's better to get MenuItem object once while creating menu, and then just call setVisible each time menu occures on screen:

    MenuItem mDynamicMenuItem;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        // Get dynamic menu item
        mDynamicMenuItem = menu.findItem(R.id.menu_item);
        return true;
    }

    // Prepare the Screen's standard options menu to be displayed. This is called right 
    // before the menu is shown, every time it is shown. You can use this method to
    // efficiently enable/disable items or otherwise dynamically modify the contents.
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
        // Here is just a good place to update item
        mDynamicMenuItem.setVisible(isVisible);
        return true;
    }
Trueman answered 28/7, 2013 at 6:44 Comment(1)
this method doesn't work when there are only one item in the menu.Panacea
L
6

You probably need to call super.onPrepareOptionsMenu after you are finished making your changes. From the docs:

Deriving classes should always call through to the base class implementation.

Limitative answered 16/11, 2010 at 23:2 Comment(0)
B
3

I got the solution. You are basically deleting the MenuItem when calling removeItem() thus also deleting the reference. Using this code works.

private boolean isStarted = false;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case 1:
        isStarted = true;
        return true;
    case 0:
        isStarted = false;
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {

    if(isStarted) {
        menu.removeItem(1);
        menu.add(0, 0, 0, "Stop");
    } else {
        menu.removeItem(0);
        menu.add(0, 1, 0, "Start");
    }

    return super.onPrepareOptionsMenu(menu);
}

You have to create the MenuItem again. Thats also the reason for the false label. Actually you don't need the MenuInflater as you create the Menu via code so also no need for any menu XML file.

Boatman answered 16/11, 2010 at 23:10 Comment(0)
T
1

thanks for the info in this post as it solved my problem of the false labels in my menu. I did have to modify it slightly and have the final code that works well as follows in the hope it saves someone else some time and frustration. Its a slightly different solution but the main change I made was the .setVisible to either True or False, apart from that i.shadrins solution was the best fit for my needs.

    @Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);

    if(loggedIn) 
    {
        logIn.setVisible(false);
        logOut.setVisible(true);
    } 
    else 
    {
        logIn.setVisible(true);
        logOut.setVisible(false);
    }
    return true;
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    logIn = menu.findItem(R.id.loggedOut);
    logOut = menu.findItem(R.id.loggedIn);
    return true;
}
Twocycle answered 11/9, 2013 at 4:16 Comment(1)
In which file it should be placed?Holman
F
0

On Android 3.0 and higher, you should call invalidateOptionsMenu() to request that the system calls onPrepareOptionsMenu(). You can then modify the options menu in the method. You can check the Changing menu items at runtime section of the Android documentation here https://developer.android.com/guide/topics/ui/menus#options-menu for more details.

Fellatio answered 1/8, 2018 at 10:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.