139

How to change MenuItem icon in ActionBar programmatically? I tried to use

MenuItem menuItem = (MenuItem)findViewById(R.id.action_settings);
menuItem.setIcon(getResources().getDrawable(R.drawable.ic_launcher))

but it doesn't work. This is my code:

MainActivity

package com.test;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;

public class MainActivity extends ActionBarActivity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MenuItem menuItem = (MenuItem)findViewById(R.id.action_settings);
                menuItem.setIcon(getResources().getDrawable(R.drawable.ic_launcher));
            }
        });
    }

    @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);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

main.xml

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

    <item
        android:icon="@drawable/action_settings"
        android:id="@+id/action_settings"
        android:title="@string/action_settings"
        android:orderInCategory="100"
        app:showAsAction="always"/>
</menu>

activity_main

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent">
    <Button
        android:id="@+id/button"
        android:text="Set icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

This is the exception that i've had after running:

MenuItem menuItem = (MenuItem)findViewById(R.id.action_settings);


11-09 19:52:40.471    1735-1735/com.test E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.ClassCastException: android.support.v7.internal.view.menu.ActionMenuItemView
            at com.test.MainActivity$1.onClick(MainActivity.java:19)
            at android.view.View.performClick(View.java:2485)
            at android.view.View$PerformClick.run(View.java:9080)
            at android.os.Handler.handleCallback(Handler.java:587)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:123)
            at android.app.ActivityThread.main(ActivityThread.java:3683)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:507)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
            at dalvik.system.NativeStart.main(Native Method)
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
veinhorn
  • 2,363
  • 6
  • 21
  • 33

9 Answers9

296

You can't use findViewById() on menu items in onCreate() because the menu layout isn't inflated yet. You could create a global Menu variable and initialize it in the onCreateOptionsMenu() and then use it in your onClick().

private Menu menu;

In your onCreateOptionsMenu()

this.menu = menu;

In your button's onClick() method

menu.getItem(0).setIcon(ContextCompat.getDrawable(this, R.drawable.ic_launcher));
Fahima Mokhtari
  • 1,691
  • 2
  • 16
  • 30
Lalith Mohan
  • 3,836
  • 5
  • 21
  • 36
  • what about in a fragment, where there is no onCreateOptionsMenu() ? – AlleyOOP Jul 25 '15 at 22:59
  • You probably need to call a method on your Activity from your Fragment – Lalith Mohan Jul 26 '15 at 10:43
  • @LalithMohan, I tried the same thing, but it doesn't work. I could though change the font color of the title of the menu-item, i am unable to change the icon. I've posted my question here: http://stackoverflow.com/questions/36716450/setting-icons-to-the-menu-items – Akeshwar Jha Apr 19 '16 at 12:02
  • 1
    I got "getDrawable() is deprecated" error message. Possible solutions are in this thread: http://stackoverflow.com/questions/29041027/android-getresources-getdrawable-deprecated-api-22 – Alexey Jan 04 '17 at 03:38
  • getDrawable is deprecated. Anyone got a new solution? – Solo Sep 09 '17 at 13:26
  • Why is this answer upvoted and accepted? "You can't use findViewById() on menu items in onCreate() because the menu layout isn't inflated yet." The OP didn't use findViewById() on menu items in onCreate(), but in **onClick()**. AFAIK onClick() shouldn't get called until well after the menu is inflated. Moreover, the ClassCastException is due to a different problem, namely that the OP is trying to cast a ActionMenuItemView to a MenuItem. – LarsH Apr 22 '19 at 20:50
54

Lalith's answer is correct.

You may also try this approach:

button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            invalidateOptionsMenu();
        }
    });

 @Override
 public boolean onPrepareOptionsMenu(Menu menu) {

    MenuItem settingsItem = menu.findItem(R.id.action_settings);
    // set your desired icon here based on a flag if you like
    settingsItem.setIcon(ContextCompat.getDrawable(this, R.drawable.ic_launcher)); 

    return super.onPrepareOptionsMenu(menu);
 }
CoolMind
  • 26,736
  • 15
  • 188
  • 224
marius
  • 637
  • 7
  • 11
10

This works for me. It should be in your onOptionsItemSelected(MenuItem item) method item.setIcon(R.drawable.your_icon);

Mohale
  • 2,040
  • 3
  • 17
  • 18
6

Here is how i resolved this:

1 - create a Field Variable like: private Menu mMenuItem;

2 - override the method invalidateOptionsMenu():

@Override
public void invalidateOptionsMenu() {
    super.invalidateOptionsMenu();
}

3 - call the method invalidateOptionsMenu() in your onCreate()

4 - add mMenuItem = menu in your onCreateOptionsMenu(Menu menu) like this:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.webview_menu, menu);
    mMenuItem = menu;
    return super.onCreateOptionsMenu(menu);
}

5 - in the method onOptionsItemSelected(MenuItem item) change the icon you want like this:

 @Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()){

        case R.id.R.id.action_settings:
            mMenuItem.getItem(0).setIcon(R.drawable.ic_launcher); // to change the fav icon
            //Toast.makeText(this, " " + mMenuItem.getItem(0).getTitle(), Toast.LENGTH_SHORT).show(); <<--- this to check if the item in the index 0 is the one you are looking for
            return true;
    }
    return super.onOptionsItemSelected(item);
}
korchix
  • 1,445
  • 1
  • 19
  • 22
  • let's say I have 5 items, I need to change the icons when clicked...but when I click the next item, the prev item's icon needs to be restored..how to do that?? – Partha Paul Sep 21 '21 at 07:50
4

Instead of getViewById(), use

MenuItem item = getToolbar().getMenu().findItem(Menu.FIRST);

replacing the Menu.FIRST with your menu item id.

Alen Siljak
  • 2,482
  • 2
  • 24
  • 29
3

I resolved this problem this way:

In onCreateOptionsMenu:

this.menu = menu;
this.menu.add("calendar");
ImageView imageView = new ImageView(getActivity());
imageView.setMinimumHeight(128);
imageView.setMinimumWidth(128);
imageView.setImageDrawable(yourDrawable);
MenuItem item = this.menu.getItem(0);
item.setActionView(imageView);

in onOptionsItemSelected:

if (item.getOrder() == 0) {
    //TODO
    return true;
}
ByteHamster
  • 4,884
  • 9
  • 38
  • 53
iamthevoid
  • 438
  • 4
  • 16
1

Kotlin version:

toolbar.menu.findItem(R.id.notification).icon =
                    ContextCompat.getDrawable(requireContext(), R.drawable.ic_notification)

toolbar.menu.findItem(R.id.notification).isVisible = true
SpiralDev
  • 7,011
  • 5
  • 28
  • 42
0

to use in onMenuItemClick(MenuItem item) just do invalidateOptionsMenu(); item.setIcon(ContextCompat.getDrawable(this, R.drawable.ic_baseline_play_circle_outline_24px));

splhead
  • 390
  • 3
  • 6
-1

Its Working

      MenuItem tourchmeMenuItem; // Declare Global .......

 public boolean onCreateOptionsMenu(Menu menu) 
 {
        getMenuInflater().inflate(R.menu.search, menu);
        menu.findItem(R.id.action_search).setVisible(false);
        tourchmeMenuItem = menu.findItem(R.id.done);
        return true;
 }

    public boolean onOptionsItemSelected(MenuItem item) {

    case R.id.done:
                       if(LoginPreferences.getActiveInstance(CustomViewFinderScannerActivity.this).getIsFlashLight()){
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                mScannerView.setFlash(false);
                                LoginPreferences.getActiveInstance(CustomViewFinderScannerActivity.this).setIsFlashLight(false);
                                tourchmeMenuItem.setIcon(getResources().getDrawable(R.mipmap.torch_white_32));
                            }
                        }else {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                mScannerView.setFlash(true);
                                LoginPreferences.getActiveInstance(CustomViewFinderScannerActivity.this).setIsFlashLight(true);
                                tourchmeMenuItem.setIcon(getResources().getDrawable(R.mipmap.torch_cross_white_32));
                            }
                        }
                        break;

}
Keshav Gera
  • 10,807
  • 1
  • 75
  • 53