233

I'm trying to change the title of a menu item from outside of the onOptionsItemSelected(MenuItem item) method.

I already do the following;

public boolean onOptionsItemSelected(MenuItem item) {
  try {
    switch(item.getItemId()) {
      case R.id.bedSwitch:
        if(item.getTitle().equals("Set to 'In bed'")) {
          item.setTitle("Set to 'Out of bed'");
          inBed = false;
        } else {
          item.setTitle("Set to 'In bed'");
          inBed = true;
        }
        break;
    }
  } catch(Exception e) {
    Log.i("Sleep Recorder", e.toString());
  }
  return true;
}

however I'd like to be able to modify the title of a particular menu item outside of this method.

Samet ÖZTOPRAK
  • 3,112
  • 3
  • 32
  • 33
Garbit
  • 5,805
  • 6
  • 39
  • 72

13 Answers13

385

I would suggest keeping a reference within the activity to the Menu object you receive in onCreateOptionsMenu and then using that to retrieve the MenuItem that requires the change as and when you need it. For example, you could do something along the lines of the following:

public class YourActivity extends Activity {

  private Menu menu;
  private String inBedMenuTitle = "Set to 'In bed'";
  private String outOfBedMenuTitle = "Set to 'Out of bed'";
  private boolean inBed = false;

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

    // Create your menu...

    this.menu = menu;
    return true;
  }

  private void updateMenuTitles() {
    MenuItem bedMenuItem = menu.findItem(R.id.bedSwitch);
    if (inBed) {
      bedMenuItem.setTitle(outOfBedMenuTitle);
    } else {
      bedMenuItem.setTitle(inBedMenuTitle);
    }
  }

}

Alternatively, you can override onPrepareOptionsMenu to update the menu items each time the menu is displayed.

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
Charles Harley
  • 7,184
  • 3
  • 32
  • 38
  • 1
    I always expect Android to have a more elegant solution to these sorts of problems. Seems the simplest answers are often the best - thanks. – Steven Jan 29 '15 at 08:00
150

As JxDarkAngel suggested, calling this from anywhere in your Activity,

invalidateOptionsMenu();

and then overriding:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
  MenuItem item = menu.findItem(R.id.bedSwitch);
    if (item.getTitle().equals("Set to 'In bed'")) {
        item.setTitle("Set to 'Out of bed'");
        inBed = false;
    } else {
        item.setTitle("Set to 'In bed'");
        inBed = true;
    }
  return super.onPrepareOptionsMenu(menu);
}

is a much better choice. I used the answer from https://stackoverflow.com/a/17496503/568197

Todd DeLand
  • 3,065
  • 1
  • 26
  • 15
  • Best solution. Because this one override android method instead of reinvent the wheel. – Azlan Jamal Jul 20 '16 at 06:52
  • Just note that `onPrepareOptionsMenu()` is called fairly often by the Android framework, for example when displaying an Activity and every time the menu is displayed. So this may not be very efficient, if your menu does not change very often. – Mr-IDE Sep 30 '17 at 19:51
  • 1
    `invalidateOptionsMenu()` will also call `onCreateOptionsMenu()`, so you could put the update logic in `onCreateOptionsMenu()`. – Mr-IDE Jan 06 '19 at 14:21
  • @Garbit updated to use your code from original question! – Todd DeLand Dec 11 '19 at 14:14
  • 1
    Accepted - eternal karma awaits :) – Garbit Dec 11 '19 at 18:09
12

you can do this create a global "Menu" object then assign it in onCreateOptionMenu

public class ExampleActivity extends AppCompatActivity
    Menu menu;

then assign here

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);
    this.menu = menu;
    return true;
}

Then later use assigned Menu object to get required items

menu.findItem(R.id.bedSwitch).setTitle("Your Text");
Ridcully
  • 23,362
  • 7
  • 71
  • 86
Pranav Raut
  • 401
  • 6
  • 9
5

Create a setOptionsTitle() method and set a field in your class. Such as:

String bedStatus = "Set to 'Out of Bed'";

...

public void setOptionsTitle(String status)
{
    bedStatus = status;

}

Now when the menu gets populated, change the title to whatever your status is:

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

        menu.add(bedStatus);


        // Return true so that the menu gets displayed.
        return true;
    }
Jack
  • 9,156
  • 4
  • 50
  • 75
  • I need to be able to set it after the activity has been rendered. So therefore not inside those two methods – Garbit Aug 15 '11 at 15:30
  • Call setOptionsTitle at any point after your activity has been rendered. I guess I'm not understanding what your wanting because "I need to be able to set it after the activity has been rendered" means to me after you call setContent(R.layout.id), you might need to change what the options menu displays (which you can do with setOptionsTitle() - from any method, anywhere, anytime). – Jack Aug 15 '11 at 15:35
  • Although this approach does work it wouldn't be recommended as the Menu object that manages the menu won't know when the title has changed and therefore can't perform the tasks it may need to when the title changes, e.g layout and line breaks. – Charles Harley Aug 15 '11 at 15:48
3

You better use the override onPrepareOptionsMenu

menu.Clear ();
   if (TabActual == TabSelec.Anuncio)
   {
       menu.Add(10, 11, 0, "Crear anuncio");
       menu.Add(10, 12, 1, "Modificar anuncio");
       menu.Add(10, 13, 2, "Eliminar anuncio");
       menu.Add(10, 14, 3, "Actualizar");
   }
   if (TabActual == TabSelec.Fotos)
   {
       menu.Add(20, 21, 0, "Subir foto");
       menu.Add(20, 22, 1, "Actualizar");
   }
   if (TabActual == TabSelec.Comentarios)
   {
       menu.Add(30, 31, 0, "Actualizar");
   }

Here an example

Nunser
  • 4,512
  • 8
  • 25
  • 37
  • Indeed, use the intended approach. :) If you decide to keep a local reference to the menu you'll need to worry about context leaks I would think. Or maybe not. But certainly not with this approach. – William T. Mallard Jan 27 '15 at 20:35
3

I use this code to costum my bottom navigation item

BottomNavigationView navigation = this.findViewById(R.id.my_bottom_navigation);
Menu menu = navigation.getMenu();
menu.findItem(R.id.nav_wall_see).setTitle("Hello");
Hulk
  • 6,399
  • 1
  • 30
  • 52
Oumar
  • 31
  • 6
2

Declare your menu field.

private Menu menu;

Following is onCreateOptionsMenu() method

public boolean onCreateOptionsMenu(Menu menu) {
this.menu = menu;
    try {
        getMenuInflater().inflate(R.menu.menu_main,menu);
    } catch (Exception e) {
        e.printStackTrace();
        Log.i(TAG, "onCreateOptionsMenu: error: "+e.getMessage());
    }
    return super.onCreateOptionsMenu(menu);
}

Following will be your name setter activity. Either through a button click or through conditional code

public void setMenuName(){
menu.findItem(R.id.menuItemId).setTitle(/*Set your desired menu title here*/);
}

This worked for me.

hyperCoder
  • 271
  • 2
  • 13
1

You can do it like this, and no need to dedicate variable:

Toolbar toolbar = findViewById(R.id.toolbar);
Menu menu = toolbar.getMenu();
MenuItem menuItem = menu.findItem(R.id.some_action);
menuItem.setTitle("New title");

Or a little simplified:

MenuItem menuItem = ((Toolbar)findViewById(R.id.toolbar)).getMenu().findItem(R.id.some_action);
menuItem.setTitle("New title");

It works only - after the menu created.

IQ.feature
  • 600
  • 6
  • 16
1

You can Change Menu Item text using below Code: -

 fun showPopup(v: View) {
        popup = PopupMenu(context, v)
        val inflater = popup?.menuInflater
        popup?.setOnMenuItemClickListener(this)
        inflater?.inflate(R.menu.menu_main, popup?.menu)
        val menu: Menu = popup!!.menu
        val item = menu.findItem(R.id.name)
        if (item.title.equals("Name")) {
            item.title = "Safal Bhatia"
        }
}
Safal Bhatia
  • 245
  • 2
  • 6
0

It seems to me that you want to change the contents of menu inside a local method, and this method is called at any time, whenever an event is occurred, or in the activity UI thread.

Why don't you take the instance of Menu in the global variable in onPrepareOptionsMenu when this is overridden and use in this method of yours. Be sure that this method is called whenever an event is occurred (like button click), or in the activity UI thread, handler or async-task post-execute.

You should know in advance the index of this menu item you want to change. After clearing the menu, you need to inflate the menu XML and update your item's name or icon.

Abhinav Saxena
  • 1,990
  • 2
  • 24
  • 55
0

For people that need the title set statically. This can be done in the AndroidManifest.xml

<activity
    android:name=".ActivityName"
    android:label="Title Text" >
</activity>

Options Menu Title Text

moberme
  • 669
  • 7
  • 13
0

I needed to change the menu icon for the fragment. I altered Charles’s answer to this question a bit for the fragment:

    private Menu top_menu;

    //...
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

       setHasOptionsMenu(true);
       //...
       rootview = inflater.inflate(R.layout.first_content,null);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.fragment_menu, menu);
        this.top_menu = menu;
    }


    // my procedure
    private void updateIconMenu() {
         if(top_menu!= null) {
             MenuItem nav_undo = top_menu.findItem(R.id.action_undo);
             nav_undo.setIcon( R.drawable.back);
         }
    }
gevaraweb
  • 912
  • 7
  • 19
0

I hit this problem too. In my case I wanted to set the string to reflect additional information using getString.

As stated above you need to find the correct menuItem in the menu and set it in the onPrepareOptionsMenu method. The solutions above didn't handle the case where the item was in a sub menu and for this you need to search the submenu for the item. I wrote a little Kotlin recursive function to allow me to this for multiple items. Code below...

override fun onPrepareOptionsMenu(menu: Menu) {
...
    menu.menuSetText(R.id.add_new_card,
        getString(R.string.add_card, currentDeck.deckName))
...
}
private fun Menu.getMenuItem(idx: Int, itemId: Int): MenuItem? {
    Log.d(TAG, "getMenuItem: $idx of ${this.size()}")
    if (idx >= size()) return null
    val item = getItem(idx)
    if (item.hasSubMenu()) {
        val mi = item.subMenu.getMenuItem(0, itemId)
        // mi non-null means we found item.
        if (mi != null)
            return mi
    }
    if (item != null && item.itemId == itemId)
        return item
    return getMenuItem(idx + 1, itemId)
}
fun Menu.menuSetText(itemId: Int, title: String) {
    val menuItem = getMenuItem(0, itemId)
    if (menuItem != null)
        menuItem.title = title
    else
        Log.e(TAG,
            "menuSetText to \"$title\": Failed to find ${
                "itemId:0x%08x".format(itemId)}"
        )
}
steven smith
  • 1,519
  • 15
  • 31