Android: come abilitare / disabilitare la voce di menu delle opzioni al clic sul pulsante?


127

Posso facilmente farlo quando sto usando onCreateOptionsMenuo onOptionsItemSelectedmetodi.

Ma ho un pulsante da qualche parte nella schermata e, facendo clic su quel pulsante, dovrebbe abilitare / disabilitare le voci del menu di scelta rapida.

Risposte:


272

Ad ogni modo, la documentazione copre tutte le cose.

Modifica delle voci di menu in fase di esecuzione

Una volta creata l'attività, il onCreateOptionsMenu()metodo viene chiamato solo una volta, come descritto sopra. Il sistema conserva e riutilizza il valore Menudefinito in questo metodo fino a quando l'attività non viene distrutta. Se si desidera modificare il menu Opzioni in qualsiasi momento dopo la sua prima creazione, è necessario sostituire il onPrepareOptionsMenu()metodo. Questo ti passa l'oggetto Menu come esiste attualmente. Ciò è utile se desideri rimuovere, aggiungere, disabilitare o abilitare le voci di menu in base allo stato corrente dell'applicazione.

Per esempio

@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;
}

Su Android 3.0 e versioni successive, il menu delle opzioni è considerato sempre aperto quando le voci di menu sono presentate nella barra delle azioni. Quando si verifica un evento e si desidera eseguire un aggiornamento del menu, è necessario chiamare invalidateOptionsMenu()per richiedere la chiamata di sistema onPrepareOptionsMenu().


2
setEnable()cambia ciò che accade quando si preme questo menu ma non cambia l'aspetto (cosa c'è che non va, sviluppatori Android?). Quindi è più chiaro disabilitare o cambiare il titolo, o preferibilmente solo rendere MenuIteminvisibile.
Vlad,

19
Suggerimento rapido: ritorna falseper disabilitare completamente il menu.
Bart Friederichs,

5
Inoltre, il commento dell'API su onPrepareOptionsMenu afferma chiaramente: le classi di derivazione devono sempre (!) Chiamare l'implementazione della classe di base. Hai dimenticato la tua super chiamata lì.
AgentKnopf,


Come si conosce l'ID intero di MenuItem aggiunto in fase di esecuzione? Puoi solo aggiungerli per nome.
Antonio Sesto,

66

Su tutte le versioni di Android, il modo più semplice: usalo per MOSTRARE un'icona di azione di menu come disabilitata E renderla FUNZIONE anche come disabilitata:

@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
Perché impostare alpha su 0 quando è possibile impostare la visibilità su false?
MLProgrammer-CiM,

8
Non sto impostando l'alfa su 0, ma su 130.
Frank,

8
Dipende dal contesto del pulsante. Se la funzione che il pulsante servirebbe normalmente è completamente inutilizzabile nello stato attuale, allora sì la visibilità dovrebbe essere invisibile / sparita. Tuttavia, se la funzione che il pulsante normalmente servirebbe POTREBBE essere utilizzabile per qualsiasi motivo (ad es. Se l'utente diventa un membro premium, se l'utente accede, se l'utente si connette a Internet, ecc.) Allora è bello averlo disattivato perché quindi consente all'utente di sapere che esiste qualche funzione a cui non hanno accesso per qualche motivo.
yiati,

6
L'impostazione dell'icona su invisibile non è migliore in quasi tutti i casi d'uso. Nel caso in cui abbiate un gruppo, è meglio che rimangano nelle loro posizioni e in grigio indica all'utente che esiste un'opzione che può essere abilitata in un determinato stato del programma. rendere le cose invisibili e invisibili e probabilmente causare cambiamenti di layout è molto sciocco. Esiste un motivo per cui la maggior parte dei menu oscura gli elementi e non li rimuove a seconda della modalità.
RichieHH,

1
Come se il menu non contenesse l'icona? Non puoi impostare Alpha ().
Latief Anwar,

42

È possibile salvare l'elemento come variabile durante la creazione del menu delle opzioni e quindi modificarne le proprietà a piacimento.

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

Questa è la risposta corretta a qualsiasi versione di Android. La risposta convalidata è valida solo per i dispositivi API 11>.
Marco HC,

2
Ci ho provato e non funziona. Volevi dire onPrepareOptionsMenu?
Christopher Pickslay,

6

semplifica la versione di @Vikas

@Override
public boolean onPrepareOptionsMenu (Menu menu) {

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

5

Come aggiornare il menu corrente al fine di abilitare o disabilitare gli elementi quando viene eseguito un AsyncTask.

Nel mio caso d'uso avevo bisogno di disabilitare il mio menu mentre il mio AsyncTask stava caricando i dati, quindi dopo aver caricato tutti i dati, dovevo abilitare nuovamente tutto il menu per consentire all'utente di utilizzarlo.

Ciò ha impedito all'app di consentire agli utenti di fare clic sulle voci di menu durante il caricamento dei dati.

Per prima cosa, dichiaro una variabile di stato, se la variabile è 0 viene mostrato il menu, se quella variabile è 1 il menu è nascosto.

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

Quindi nel mio onCreateOptionsMenu()controllo per questa variabile, se è 1 disabilito tutti i miei articoli, in caso contrario, li mostro solo tutti

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

Ora, quando inizia la mia attività, onCreateOptionsMenu()verrà chiamato solo una volta e tutti i miei oggetti spariranno perché ho impostato lo stato per loro all'inizio.

Quindi creo un AsyncTask dove ho impostato la variabile di stato su 0 nel mio onPostExecute()

Questo passaggio è molto importante!

Quando lo chiami invalidateOptionsMenu();, verrà riavviatoonCreateOptionsMenu();

Quindi, dopo aver impostato il mio stato su 0, ho appena ridisegnato tutto il menu ma questa volta con la mia variabile su 0, detto questo, tutto il menu verrà mostrato dopo che tutto il processo asincrono è terminato, e quindi il mio utente può usare il 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

        }
    }

risultati

inserisci qui la descrizione dell'immagine


2

la migliore soluzione quando si esegue sul cassetto di navigazione

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

Questo nasconde l'intero menu e rende impossibile riaprirlo
MrStahlfelge

2

Una risposta più moderna per una vecchia domanda:

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>

Ottimo approccio che può essere utilizzato senza molta caldaia in tutta l'app.
Arthur,

Che problema hai?
ExpensiveBelly,

@ExpensiveBelly non è un problema in sé, solo un avviso pubblico.
Big McLarge: enorme

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

Dalla recensione: Ciao, per favore non rispondere solo con il codice sorgente. Prova a fornire una bella descrizione del funzionamento della tua soluzione. Vedi: Come posso scrivere una buona risposta? . Grazie
sɐunıɔ ןɐ qɐp

1

Quello che ho fatto è stato salvare un riferimento al menu in onCreateOptionsMenu. Questo è simile alla risposta di Nir tranne che invece di salvare ogni singolo elemento, ho salvato l'intero menu.

Dichiara un menu Menu toolbarMenu;.

Quindi, onCreateOptionsMenusalva il menu nella tua variabile

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

Ora puoi accedere al tuo menu e a tutti i suoi elementi ogni volta che vuoi. 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
Sebbene questo codice possa rispondere alla domanda del PO, alcune parole di spiegazione aiuteranno gli utenti attuali e futuri a comprendere meglio la tua risposta.
Thom,

0

Se menu visibile

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

Se nascondi menu

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

-4

In genere è possibile modificare le proprietà delle visualizzazioni in runtime:

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

e poi...

item.setVisibility(false)

ma

se vuoi modificare la visibilità delle opzioni dal ContextMenu, premi il tuo pulsante, puoi attivare un flag, e poi su onCreateContextMenu puoi fare qualcosa del genere:

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

        }

Spero che aiuti


Devo dire che ti sbagli, voglio che la voce di menu sia disabilitata, non Button.
Vikas,

la mia risposta è completa. Questo codice funziona, l'ho usato nei miei progetti
Eric

1
Bene grazie per il lavoro, ma dovresti leggere correttamente la domanda che ho già dichiarato che posso cambiarlo nel onCreateContextMenumetodo. Ma voglio accedere al menu di scelta rapida da questo metodo.
Vikas,

onCreateContextMenuverrà chiamato solo una volta, ma posso fare clic sul pulsante molto tempo per abilitare / disabilitare la voce di menu.
Vikas,

Sì, ma il menu di scelta rapida viene normalmente nascosto. Se premi il "pulsante da qualche parte" e imposti la bandiera come ho detto, questo menu contestuale non è visibile e la prossima volta che ricarichi il menu contestuale, questa opzione sarà invisibile. Un'altra opzione è quella di fare un altro tipo di menu con lo stesso aspetto per gestire gli eventi con un altro metodo.
Eric,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.