Comment modifier l'icône MenuItem dans ActionBar par programmation

122

Comment changer l'icône MenuItem dans ActionBar par programme? J'ai essayé d'utiliser

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

mais ça ne marche pas. Voici mon code:

Activité principale

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>

C'est l'exception que j'ai eue après avoir exécuté:

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)
Veinhorn
la source

Réponses:

256

Vous ne pouvez pas utiliser findViewById () sur les éléments de menu dans onCreate () car la disposition du menu n'est pas encore gonflée. Vous pouvez créer une variable de menu globale et l'initialiser dans le onCreateOptionsMenu (), puis l'utiliser dans votre onClick ().

private Menu menu;

Dans votre onCreateOptionsMenu ()

this.menu = menu;

Dans la méthode onClick () de votre bouton

menu.getItem(0).setIcon(ContextCompat.getDrawable(this, R.drawable.ic_launcher));
Lalith Mohan
la source
qu'en est-il dans un fragment, où il n'y a pas de onCreateOptionsMenu ()?
AlleyOOP
Vous devez probablement appeler une méthode sur votre activité à partir de votre fragment
Lalith Mohan
@LalithMohan, j'ai essayé la même chose, mais ça ne marche pas. Je pourrais bien changer la couleur de police du titre de l'élément de menu, je ne peux pas changer l'icône. J'ai posté ma question ici: stackoverflow.com/questions/36716450/…
Akeshwar Jha
1
J'ai reçu le message d'erreur "getDrawable () is deprecated". Les solutions possibles sont dans ce fil: stackoverflow.com/questions/29041027/…
Alexey
getDrawable est obsolète. Quelqu'un a une nouvelle solution?
Solo
46

La réponse de Lalith est correcte.

Vous pouvez également essayer cette approche:

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);
 }
marius
la source
C'est la manière de procéder. +1
lasec0203
8

Cela fonctionne pour moi. Cela devrait être dans votre onOptionsItemSelected(MenuItem item)méthode item.setIcon(R.drawable.your_icon);

Mohale
la source
3

J'ai résolu ce problème de cette façon:

Dans 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);

dans onOptionsItemSelected:

if (item.getOrder() == 0) {
    //TODO
    return true;
}
iamthevoid
la source
3

Au lieu de getViewById (), utilisez

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

en remplaçant le Menu.FIRSTpar votre ID d'élément de menu.

Alen Siljak
la source
3

Voici comment j'ai résolu ceci:

1 - créez une variable de champ comme: private Menu mMenuItem;

2 - remplacez la méthode invalidateOptionsMenu ():

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

3 - appelez la méthode invalidateOptionsMenu()dans votreonCreate()

4 - ajoutez mMenuItem = menuvotre onCreateOptionsMenu(Menu menu)comme ceci:

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

5 - dans la méthode onOptionsItemSelected(MenuItem item)changez l'icône que vous voulez comme ceci:

 @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
la source
0

à utiliser dans onMenuItemClick(MenuItem item) juste faireinvalidateOptionsMenu(); item.setIcon(ContextCompat.getDrawable(this, R.drawable.ic_baseline_play_circle_outline_24px));

splhead
la source
0

Version Kotlin:

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

toolbar.menu.findItem(R.id.notification).isVisible = true
SpiralDev
la source
-1

Ça marche

      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
la source