How to change menu item text dynamically in Android
Asked Answered
M

13

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.

Moser answered 15/8, 2011 at 15:11 Comment(1)
https://mcmap.net/q/117229/-how-to-change-menu-item-text-dynamically-in-android should be the accepted answerPlaywriting
N
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://mcmap.net/q/119730/-changing-menu-item-programmatically-is-not-working-in-android

Nightingale answered 18/8, 2015 at 12:22 Comment(5)
Best solution. Because this one override android method instead of reinvent the wheel.Milne
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.Stotinka
invalidateOptionsMenu() will also call onCreateOptionsMenu(), so you could put the update logic in onCreateOptionsMenu().Stotinka
@Moser updated to use your code from original question!Nightingale
Accepted - eternal karma awaits :)Moser
G
386

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.

Greasewood answered 15/8, 2011 at 15:27 Comment(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.Steve
N
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://mcmap.net/q/119730/-changing-menu-item-programmatically-is-not-working-in-android

Nightingale answered 18/8, 2015 at 12:22 Comment(5)
Best solution. Because this one override android method instead of reinvent the wheel.Milne
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.Stotinka
invalidateOptionsMenu() will also call onCreateOptionsMenu(), so you could put the update logic in onCreateOptionsMenu().Stotinka
@Moser updated to use your code from original question!Nightingale
Accepted - eternal karma awaits :)Moser
M
13

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");
Menjivar answered 27/6, 2017 at 17:25 Comment(1)
This is first solution that i thought first and it worked thx.Banksia
S
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;
    }
Snatchy answered 15/8, 2011 at 15:17 Comment(3)
I need to be able to set it after the activity has been rendered. So therefore not inside those two methodsMoser
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).Snatchy
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.Greasewood
L
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

Longawa answered 31/5, 2013 at 1:19 Comment(1)
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.Annabel
G
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");
Goles answered 30/7, 2018 at 9:35 Comment(0)
N
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.

Nonstandard answered 15/2, 2018 at 19:57 Comment(0)
N
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.

Nissa answered 13/7, 2020 at 6:54 Comment(2)
It works if you are using standart toolbar as default theme but do not work if u use custom toolbarBanksia
Yes, the menu comes from: "Menu menu = toolbar.getMenu();" Else need to add your custom menu...Nissa
C
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"
        }
}
Cadell answered 28/7, 2022 at 11:43 Comment(0)
K
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.

Kirimia answered 20/11, 2013 at 12:26 Comment(0)
D
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

Dupery answered 7/5, 2015 at 23:59 Comment(2)
Questions is for dynamically, not statically!Yonder
still came up on google search and helped me, thanks for postingSadie
C
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);
         }
    }
Coppery answered 2/5, 2019 at 11:44 Comment(0)
H
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)}"
        )
}
Hofuf answered 8/7, 2022 at 18:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.