Android: como ativar / desativar o item de menu de opções ao clicar no botão?

127

Eu posso fazer isso facilmente quando estou usando onCreateOptionsMenuou onOptionsItemSelectedmétodos.

Mas eu tenho um botão em algum lugar na tela e, ao clicar nesse botão, ele deve ativar / desativar os itens do menu de contexto.

Vikas
fonte

Respostas:

272

De qualquer forma, a documentação cobre todas as coisas.

Alterando itens de menu em tempo de execução

Depois que a atividade é criada, o onCreateOptionsMenu()método é chamado apenas uma vez, conforme descrito acima. O sistema mantém e reutiliza o que Menuvocê define neste método até que sua atividade seja destruída. Se você deseja alterar o menu Opções a qualquer momento após a sua criação, você deve substituir o onPrepareOptionsMenu()método. Isso passa o objeto Menu como ele existe atualmente. Isso é útil se você deseja remover, adicionar, desativar ou ativar itens de menu, dependendo do estado atual do seu aplicativo.

Por exemplo

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

No Android 3.0 e superior, o menu de opções é considerado sempre aberto quando os itens de menu são apresentados na barra de ação. Quando um evento ocorre e você deseja executar uma atualização de menu, você deve ligar invalidateOptionsMenu()para solicitar a chamada do sistema onPrepareOptionsMenu().

Vikas
fonte
2
setEnable()muda o que acontece quando você pressiona esse menu, mas não muda a aparência (o que há de errado, desenvolvedores do Android?). Portanto, é mais claro desabilitar e alterar o título ou, de preferência, apenas tornar o MenuIteminvisível.
Vlad
19
Dica rápida: retorne falsepara desativar o menu completamente.
Bart Friederichs
5
Além disso, o comentário da API no onPrepareOptionsMenu afirma claramente: A derivação de classes sempre deve (!) Chamar a implementação da classe base. Você esqueceu sua chamada super lá.
AgentKnopf
Como você sabe o ID inteiro de MenuItem adicionado no tempo de execução? Você pode adicioná-los apenas pelo nome.
Antonio Sesto
66

Em todas as versões do Android, a maneira mais fácil: use isso para MOSTRAR um ícone de ação do menu como desativado E torná-lo FUNCIONADO também como desativado:

@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);
    }
}
Frank
fonte
1
Por que definir alfa como 0 quando você pode definir a visibilidade como falsa?
MLProgrammer-CiM
8
Eu não estou definindo alfa para 0, mas para 130.
Frank
8
Depende do contexto do botão. Se o recurso que o botão normalmente serviria for completamente inutilizável no estado atual, sim, a visibilidade deverá ficar invisível / desaparecida. No entanto, se o recurso que o botão normalmente servir PODE ser utilizável, seja qual for o motivo (por exemplo, se o usuário se tornar um membro premium, se o usuário fizer login, se o usuário se conectar à Internet etc.), é bom deixá-lo acinzentado. porque permite que o usuário saiba que há algum recurso existente ao qual não tem acesso por algum motivo.
Yiati
6
Definir o ícone como invisível não é melhor em quase todos os casos de uso. Caso você tenha um grupo, é melhor que ele permaneça em suas posições e acinzentado indica ao usuário que existe uma opção que pode ser ativada em um determinado estado do programa. tornar as coisas invisíveis e invisíveis e provavelmente causar alterações no layout é muito tolo. Há uma razão pela qual a maioria dos menus fica acinzentada e não os remove, dependendo do modo.
RichieHH
1
Como se o menu não contiver ícone? Você não pode definir Alpha ().
Latief Anwar
42

Você pode salvar o item como uma variável ao criar o menu de opções e, em seguida, alterar suas propriedades à vontade.

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);
}    
nir
fonte
Essa é a resposta correta para qualquer versão do Android. A resposta validada é válida apenas para dispositivos API 11>.
Marco HC
2
Eu tentei isso e não funciona. Você quis dizer onPrepareOptionsMenu?
Christopher Pickslay
6

simplifique a versão @Vikas

@Override
public boolean onPrepareOptionsMenu (Menu menu) {

    menu.findItem(R.id.example_foobar).setEnabled(isFinalized);
    return true;
}
Kosrat D. Ahmad
fonte
4

Como atualizar o menu atual para ativar ou desativar os itens quando um AsyncTask é concluído.

No meu caso de uso, eu precisava desativar meu menu enquanto o AsyncTask carregava dados; depois de carregar todos os dados, era necessário ativar todo o menu novamente para permitir que o usuário o usasse.

Isso impediu o aplicativo de permitir que os usuários clicassem nos itens de menu enquanto os dados estavam sendo carregados.

Primeiro, declaro uma variável de estado; se a variável for 0, o menu será exibido; se essa variável for 1, o menu estará oculto.

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

Então, na minha onCreateOptionsMenu()verificação dessa variável, se for 1, desativo todos os meus itens; caso contrário, apenas mostro a todos

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

Agora, quando minha Atividade iniciar, onCreateOptionsMenu()será chamada apenas uma vez e todos os meus itens desaparecerão porque eu configurei o estado para eles no início.

Em seguida, crio um AsyncTask, onde defino essa variável de estado como 0 no meu onPostExecute()

Este passo é muito importante!

Quando você ligar invalidateOptionsMenu();, será reiniciadoonCreateOptionsMenu();

Então, depois de configurar meu estado como 0, apenas redesenhei todo o menu, mas desta vez com a variável 0, ou seja, todo o menu será exibido depois que todo o processo assíncrono estiver concluído, e então meu usuário poderá usar o 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

        }
    }

Resultados

insira a descrição da imagem aqui

Gastón Saillén
fonte
2

a melhor solução quando você executa na gaveta de navegação

@Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.setGroupVisible(0,false);
        return true;
    }
Prashant Gosai
fonte
Isto esconde todo o menu e torna impossível abri-lo novamente
MrStahlfelge
2

Uma resposta mais moderna para uma pergunta antiga:

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>
ExpensiveBelly
fonte
Ótima abordagem que pode ser usada sem muito clichê em todo o aplicativo.
Arthur
Qual problema você está tendo?
ExpensiveBelly
@ExpensiveBelly não é um problema em si, apenas aviso público.
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);
     }
Tousif Akram
fonte
Da avaliação: Olá, por favor, não responda apenas com o código fonte. Tente fornecer uma boa descrição sobre como sua solução funciona. Veja: Como escrevo uma boa resposta? . Obrigado
sɐunıɔ ןɐ qɐp 11/11/19
1

O que fiz foi salvar uma referência ao Menu em onCreateOptionsMenu. Isso é semelhante à resposta de nir, exceto que, em vez de salvar cada item individual, salvei o menu inteiro.

Declare um menu Menu toolbarMenu;.

Em seguida, onCreateOptionsMenusalve o menu na sua variável

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

Agora você pode acessar seu menu e todos os itens a qualquer momento. toolbarMenu.getItem(0).setEnabled(false);

Smitty-Werben-Jager-Manjenson
fonte
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;
}
Draken
fonte
2
Embora esse código possa responder à pergunta do OP, algumas palavras explicativas ajudarão os usuários atuais e futuros a entender sua resposta ainda melhor.
Thom
0

Se menu visível

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

Se ocultar menu

menu.findItem(R.id.id_name).setVisible(false);
murugan mani
fonte
-4

Geralmente pode alterar as propriedades de suas visualizações em tempo de execução:

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

e depois...

item.setVisibility(false)

mas

se você deseja modificar a visibilidade das opções no menu de contexto, pressione o botão, você pode ativar um sinalizador e, em seguida, no menu Criar menu, você pode fazer algo assim:

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

        }

Eu espero que isso ajude

Eric
fonte
Devo dizer que você está errado, quero que o item de menu seja desativado, não o botão.
Vikas 26/03
minha resposta está completa. Este código funciona, eu usei em meus projetos
Eric
1
Bem, obrigado pelo trabalho, mas você deve ler a pergunta corretamente, já afirmei que posso alterá-la no onCreateContextMenumétodo. Mas eu quero acessar o menu de contexto fora desse método.
Vikas 26/03
onCreateContextMenuserá chamado apenas uma vez, mas posso clicar no botão por muito tempo para ativar / desativar o item de menu.
Vikas 26/03
Sim, mas o menu de contexto normalmente é feito para ficar oculto. Se você pressionar o botão 'em algum lugar' e definir a sinalização como eu disse, esse menu de contexto não estará visível e na próxima vez que você recarregar o menu de contexto, essa opção ficará invisível. Outra opção é criar outro tipo de menu com a mesma aparência para manipular os eventos com outros métodos.
Eric