Android: Comment activer / désactiver l'élément de menu d'options lors d'un clic sur le bouton?


127

Je peux facilement le faire lorsque j'utilise des méthodes onCreateOptionsMenuou onOptionsItemSelected.

Mais j'ai un bouton quelque part dans l'écran, et en cliquant sur ce bouton, il devrait activer / désactiver les éléments du menu contextuel.

Réponses:


272

Quoi qu'il en soit, la documentation couvre toutes les choses.

Modification des éléments de menu lors de l'exécution

Une fois l'activité créée, la onCreateOptionsMenu()méthode n'est appelée qu'une seule fois, comme décrit ci-dessus. Le système conserve et réutilise le que Menuvous définissez dans cette méthode jusqu'à ce que votre activité soit détruite. Si vous souhaitez modifier le menu Options à tout moment après sa création, vous devez remplacer la onPrepareOptionsMenu()méthode. Cela vous passe l'objet Menu tel qu'il existe actuellement. Ceci est utile si vous souhaitez supprimer, ajouter, désactiver ou activer des éléments de menu en fonction de l'état actuel de votre application.

Par exemple

@Override
public boolean onPrepareOptionsMenu (Menu menu) {
    if (isFinalized) {
        menu.getItem(1).setEnabled(false);
        // You can also use something like:
        // menu.findItem(R.id.example_foobar).setEnabled(false);
    }
    return true;
}

Sur Android 3.0 et supérieur, le menu d'options est considéré comme toujours ouvert lorsque les éléments de menu sont présentés dans la barre d'actions. Lorsqu'un événement se produit et que vous souhaitez effectuer une mise à jour du menu, vous devez appeler invalidateOptionsMenu()pour demander que le système appelle onPrepareOptionsMenu().


2
setEnable()change ce qui se passe lorsque vous appuyez sur ce menu mais ne change pas son apparence (qu'est-ce qui ne va pas, développeurs Android?). Il est donc plus clair de désactiver et de modifier le titre, ou de préférence simplement de rendre MenuIteminvisible.
Vlad

19
Petite astuce: revenez falsepour désactiver complètement le menu.
Bart Friederichs

5
De plus, le commentaire de l'API sur onPrepareOptionsMenu indique clairement: Les classes dérivées doivent toujours (!) Appeler l'implémentation de la classe de base. Vous avez oublié votre super appel là-bas.
AgentKnopf


Comment connaissez-vous l'ID entier de MenuItem ajouté au moment de l'exécution? Vous ne pouvez les ajouter que par leur nom.
Antonio Sesto

66

Sur toutes les versions d'Android, le moyen le plus simple: utilisez ceci pour AFFICHER une icône d'action de menu comme désactivée ET la rendre FONCTION aussi désactivée:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {

    MenuItem item = menu.findItem(R.id.menu_my_item);

    if (myItemShouldBeEnabled) {
        item.setEnabled(true);
        item.getIcon().setAlpha(255);
    } else {
        // disabled
        item.setEnabled(false);
        item.getIcon().setAlpha(130);
    }
}

1
Pourquoi définir alpha sur 0 alors que vous pouvez définir la visibilité sur false?
MLProgrammer-CiM

8
Je ne mets pas alpha à 0, mais à 130.
Frank

8
Dépend du contexte du bouton. Si la fonction que le bouton servirait normalement est complètement inutilisable dans l'état actuel, alors oui, la visibilité devrait être invisible / disparue. Cependant, si la fonctionnalité que le bouton servirait normalement POURRAIT être utilisable pour quelque raison que ce soit (par exemple, si l'utilisateur devient un membre premium, si l'utilisateur se connecte, si l'utilisateur se connecte à Internet, etc.), alors c'est bien de l'avoir grisé parce que cela permet à l'utilisateur de savoir qu'il existe une fonctionnalité existante à laquelle il n'a pas accès pour une raison quelconque.
yiati

6
Définir l'icône sur invisible n'est pas mieux dans presque tous les cas d'utilisation. Dans le cas où vous avez un groupe, il vaut mieux qu'ils restent dans leurs positions et grisé indique à l'utilisateur qu'il existe une option qui peut être activée dans un certain état du programme. rendre quelque chose invisible et invisible et causer probablement des changements de mise en page est très ridicule. Il y a une raison pour laquelle la plupart des menus sont grisés et ne les ont pas supprimés selon le mode.
RichieHH

1
Comment si le menu ne contient pas d'icône? Vous ne pouvez pas définirAlpha ().
Latief Anwar

42

Vous pouvez enregistrer l'élément en tant que variable lors de la création du menu d'options, puis modifier ses propriétés à volonté.

private MenuItem securedConnection;
private MenuItem insecuredConnection;

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.connect_menu, menu);
    securedConnection = menu.getItem(0);
    insecuredConnection =  menu.getItem(1);
    return true;
}

public void foo(){
       securedConnection.setEnabled(true);
}    

C'est la bonne réponse à n'importe quelle version d'Android. La réponse validée n'est valide que pour les appareils API 11>.
Marco HC

2
J'ai essayé ça, et ça ne marche pas. Voulez-vous dire onPrepareOptionsMenu?
Christopher Pickslay le

6

simplifier la version @Vikas

@Override
public boolean onPrepareOptionsMenu (Menu menu) {

    menu.findItem(R.id.example_foobar).setEnabled(isFinalized);
    return true;
}

5

Comment mettre à jour le menu actuel afin d'activer ou de désactiver les éléments lorsqu'une AsyncTask est effectuée.

Dans mon cas d'utilisation, je devais désactiver mon menu pendant que mon AsyncTask chargeait des données, puis après avoir chargé toutes les données, je devais réactiver tout le menu afin de permettre à l'utilisateur de l'utiliser.

Cela a empêché l'application de permettre aux utilisateurs de cliquer sur les éléments de menu pendant le chargement des données.

Tout d'abord, je déclare une variable d'état, si la variable est 0 le menu est affiché, si cette variable est 1 le menu est masqué.

private mMenuState = 1; //I initialize it on 1 since I need all elements to be hidden when my activity starts loading.

Ensuite, dans mon onCreateOptionsMenu()je vérifie cette variable, si c'est 1 je désactive tous mes articles, sinon, je les montre simplement

 @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.menu_galeria_pictos, menu);

        if(mMenuState==1){
            for (int i = 0; i < menu.size(); i++) {
                menu.getItem(i).setVisible(false);
            }
        }else{
             for (int i = 0; i < menu.size(); i++) {
                menu.getItem(i).setVisible(true);
            }
        }

        return super.onCreateOptionsMenu(menu);
    }

Désormais, lorsque mon activité démarre, elle onCreateOptionsMenu()ne sera appelée qu'une seule fois et tous mes éléments auront disparu car j'ai défini leur état au début.

Ensuite, je crée une AsyncTask où je mets cette variable d'état à 0 dans mon onPostExecute()

Cette étape est très importante!

Lorsque vous appelez, invalidateOptionsMenu();il redémarreraonCreateOptionsMenu();

Donc, après avoir configuré mon état à 0, je viens de redessiner tout le menu mais cette fois avec ma variable sur 0, cela dit, tout le menu sera affiché une fois que tout le processus asynchrone est terminé, puis mon utilisateur peut utiliser le menu .

 public class LoadMyGroups extends AsyncTask<Void, Void, Void> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mMenuState = 1; //you can set here the state of the menu too if you dont want to initialize it at global declaration. 

        }

        @Override
        protected Void doInBackground(Void... voids) {
           //Background work

            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);

            mMenuState=0; //We change the state and relaunch onCreateOptionsMenu
            invalidateOptionsMenu(); //Relaunch onCreateOptionsMenu

        }
    }

Résultats

entrez la description de l'image ici


2

la meilleure solution lorsque vous effectuez sur le tiroir de navigation

@Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.setGroupVisible(0,false);
        return true;
    }

Cela masque tout le menu et rend impossible de l'ouvrir à nouveau
MrStahlfelge

2

Une réponse plus moderne à une vieille question:

MainActivity.kt

private var myMenuIconEnabled by Delegates.observable(true) { _, old, new ->
    if (new != old) invalidateOptionsMenu()
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    findViewById<Button>(R.id.my_button).setOnClickListener { myMenuIconEnabled = false }
}

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.menu_main_activity, menu)
    return super.onCreateOptionsMenu(menu)
}

override fun onPrepareOptionsMenu(menu: Menu): Boolean {
    menu.findItem(R.id.action_my_action).isEnabled = myMenuIconEnabled
    return super.onPrepareOptionsMenu(menu)
}

menu_main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
    android:id="@+id/action_my_action"
    android:icon="@drawable/ic_my_icon_24dp"
    app:iconTint="@drawable/menu_item_icon_selector"
    android:title="My title"
    app:showAsAction="always" />
</menu>

menu_item_icon_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?enabledMenuIconColor" android:state_enabled="true" />
<item android:color="?disabledMenuIconColor" />

attrs.xml

<resources>   
    <attr name="enabledMenuIconColor" format="reference|color"/>
    <attr name="disabledMenuIconColor" format="reference|color"/>
</resources>

styles.xml or themes.xml

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="disabledMenuIconColor">@color/white_30_alpha</item>
    <item name="enabledMenuIconColor">@android:color/white</item>

Excellente approche qui peut être utilisée sans trop de passe-partout dans l'application.
Arthur

Quel problème rencontrez-vous?
ExpensiveBelly

@ExpensiveBelly n'est pas un problème en soi, juste un avis public.
Big McLargeHuge

1
  @Override
        public boolean onOptionsItemSelected(MenuItem item) {

            switch (item.getItemId()) {

                case R.id.item_id:

                       //Your Code....

                        item.setEnabled(false);
                        break;
              }
            return super.onOptionsItemSelected(item);
     }

De l'avis: Bonjour, ne répondez pas uniquement avec le code source. Essayez de fournir une belle description du fonctionnement de votre solution. Voir: Comment écrire une bonne réponse? . Merci
sɐunıɔ ןɐ qɐp

1

Ce que j'ai fait, c'est enregistrer une référence au menu à onCreateOptionsMenu. Ceci est similaire à la réponse de nir sauf qu'au lieu d'enregistrer chaque élément individuel, j'ai enregistré le menu entier.

Déclarez un menu Menu toolbarMenu;.

Ensuite, onCreateOptionsMenuenregistrez le menu dans votre variable

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

Vous pouvez désormais accéder à votre menu et à tous ses éléments à tout moment. toolbarMenu.getItem(0).setEnabled(false);


0
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    // getMenuInflater().inflate(R.menu.home, menu);
    return false;
}

2
Bien que ce code puisse répondre à la question du PO, quelques mots d'explication aideront les utilisateurs actuels et futurs à mieux comprendre votre réponse.
Thom

0

Si menu visible

menu.findItem(R.id.id_name).setVisible(true);

Si masquer le menu

menu.findItem(R.id.id_name).setVisible(false);

-4

Généralement, vous pouvez modifier les propriétés de vos vues lors de l'exécution:

(Button) item = (Button) findViewById(R.id.idBut);

puis...

item.setVisibility(false)

mais

si vous souhaitez modifier la visibilité des options du ContextMenu, en appuyant sur votre bouton, vous pouvez activer un drapeau, puis dans onCreateContextMenu vous pouvez faire quelque chose comme ceci:

 @Override
        public void onCreateContextMenu(ContextMenu menu, 
                View v,ContextMenu.ContextMenuInfo menuInfo) {

            super.onCreateContextMenu(menu, v, menuInfo);

                menu.setHeaderTitle(R.string.context_title);

                if (flagIsOn()) {
                    addMenuItem(menu, "Option available", true);
                } else {
                    Toast.makeText(this, "Option not available", 500).show();
                }

        }

J'espère que ça aide


Je dois dire que vous vous trompez, je veux que l'élément de menu soit désactivé, pas Button.
Vikas

ma réponse est terminée. Ce code ça marche, je l'ai utilisé dans mes projets
Eric

1
Eh bien merci pour le travail, mais vous devriez lire correctement la question que j'ai déjà déclaré que je peux la changer de onCreateContextMenuméthode. Mais je veux accéder au menu contextuel en dehors de cette méthode.
Vikas

onCreateContextMenune sera appelé qu'une seule fois, mais je peux cliquer sur le bouton plusieurs fois pour activer / désactiver l'élément de menu.
Vikas

Oui, mais le menu contextuel est normalement fait pour être caché. Si vous appuyez sur votre «bouton quelque part» et définissez le drapeau comme je l'ai dit, ce menu contextuel n'est pas visible et la prochaine fois que vous rechargerez votre menu contextuel, cette option sera invisible. Une autre option est de faire un autre type de menu avec la même apparence pour gérer les événements avec une autre méthode.
Eric
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.