Chexxor
Chexxor

Reputation: 416

Changing menu items on a toolbar menu made from a xml layout

So I have this toolbar in my app, and I want to display different menu items depending on whether the user is logged in or not. When the user logs in or out I want to update my layout which for now is the toolbar menu to represent the change. For some reason though, my menu items are not removed at all, all of them are visible at all times, regardless of the login state.

My menu items:

<menu
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_add"
        android:icon="@drawable/ic_action_add"
        android:title="@string/action_add"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@+id/action_login"
        android:icon="@drawable/ic_action_logged_out"
        android:title="@string/action_log_in"
        app:showAsAction="always"/>

    <item
        android:id="@+id/action_logout"
        android:icon="@drawable/ic_action_logged_in"
        android:title="@string/action_log_out"
        app:showAsAction="always"/>
</menu>

The first menu item is only supposed to be visible to a user that is logged in. Also I guess it's self explanatory but I only want one of the log in/out buttons to be visible depending on the login state.

My Java code:

protected void initializeToolbar(){
    myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
    menu = myToolbar.getMenu();
    resetToolbarMenu();
    myToolbar.setOnMenuItemClickListener(this);
}

private void resetToolbarMenu(){
    menu.clear();
    getMenuInflater().inflate(R.menu.menu, menu);
    if(loginPrefs.getBoolean("login", false)) { //loginPrefs is reference to a SharedPreference object
        menu.removeItem(1);
    } else {
        menu.removeItem(2);
        menu.removeItem(0);
    }
}

Reason I got two methods is that I only want to set up the toolbar and listener once, but I want to be able to change the menu every time the user logs in/out without reloading the page.

After a successful login the resetToolbarMenu() method will be called again.

I suppose the menu.remove(0) does not update the UI, but I could not find another way to reach my menu object without first inflating it and then getting it from the toolbar, and I assume the inflation is what decides what items are visible. Basically, I could not find a way to remove any menu items before inflating or updating the UI in another way than inflating.

Solution:

I changed my java code into something like this:

protected void initializeToolbar(){
    myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(myToolbar);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);
    return super.onCreateOptionsMenu(menu); // Don't know if this is necessary or if returning true is prefered.
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    if(loginPrefs.getBoolean("login", false)) {
        menu.getItem(0).setVisible(true);
        menu.getItem(1).setVisible(false);
        menu.getItem(2).setVisible(true);
    } else {
        menu.getItem(0).setVisible(false);
        menu.getItem(1).setVisible(true);
        menu.getItem(2).setVisible(false);
    }
    return true;
}

I also had to call invalidateOptionsMenu() on logout/login to update the toolbar/menu. However onPrepareOptionsMenu() is also automatically called whenever you open the menu for items that aren't shown on the toolbar itself.

PS: OnCreateOptionsMenu and OnPrepareOptionsMenu will not be used unless you remember to setSupportActionBar(myToolbar) as I forgot.

Upvotes: 4

Views: 3770

Answers (2)

tompee
tompee

Reputation: 1408

You can create options menu by overriding onCreateOptionsMenu. You can create 2 xml and inflate either one of them depending on your logic. To force a redraw of the menu, you can call invalidateOptionsMenu.

For example

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    if (login) {
         inflater.inflate(R.menu.login_menu, menu);
    } else {
         inflater.inflate(R.menu.logout_menu, menu);
    }
    return true;
}

And outside change the flag and force redraw

login = false; // or true
invalidateOptionsMenu();

Upvotes: 4

bogdanN
bogdanN

Reputation: 193

You have to override onPrepareOptionsMenu in the activity to change the items in the menu.

From the documentation:

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.

Upvotes: 1

Related Questions