Como atualizar um item de menu mostrado na ActionBar?

93

Tenho uma atividade que tem 2 fragmentos. Ambos são ListFragments e contribuem com MenuItems para o Menu. Eu tenho um MenuItem que configurei o atributo android: showAsAction para que seja mostrado como um botão na ActionBar. O que funciona bem.

Agora o MenuItem é dependente do estado. É uma opção de menu Pausar / Reiniciar para pausar e retomar uma fila. Meu problema é que não consigo descobrir como definir sua estátua inicial quando o fragmento é criado.

Seu estado depende se a fila está pausada ou não. Portanto, tenho um AsyncTask que obtém a fila e define um booleano (pausado) com base no estado da fila. Estou chamando onPrepareOptionsMenu para definir o texto para o item de menu Pausa com base no último estado conhecido da fila e isso funciona muito bem se eu deixar o MenuItem no menu real. Você toca no ícone do menu e onPrepareOptionsMenu é disparado e o menu é atualizado antes de ser exibido.

O problema é que, se eu colocar esse mesmo MenuItem na ActionBar (showAsAction), como posso forçá-lo a atualizar sem ter que chamar onPrepareOptionsMenu? Preciso ser capaz de fazer isso porque na primeira inicialização do aplicativo, envio uma solicitação para obter a fila, mas a tarefa retorna após a ActionBar ser configurada e exibida. Eu criei um manipulador em meu fragmento que é chamado sempre que recebo uma atualização de fila, mas a partir daí, como posso atualizar o texto do meu MenuItem na ActionBar? Não consigo encontrar uma maneira de fazer com que o Menu definido atualmente para manipulá-lo, exceto em onPrepareOptionMenu.

Rob W.

brockoli
fonte

Respostas:

174

Opção nº 1: Experimente invalidateOptionsMenu(). Não sei se isso forçará um redesenho imediato da barra de ação ou não.

Opção nº 2: veja se getActionView()retorna algo para os afetados MenuItem. É possível que showAsActionsimplesmente crie automaticamente visualizações de ação para você. Nesse caso, você pode provavelmente ativar / desativar isso View.

Não consigo encontrar uma maneira de fazer com que o Menu definido atualmente para manipulá-lo, exceto em onPrepareOptionMenu.

Você pode pendurar no Menuobjeto que recebeu onCreateOptionsMenu(). Citando os documentos :

Você pode segurar o menu com segurança (e quaisquer itens criados a partir dele), fazendo modificações conforme desejado, até a próxima vez que onCreateOptionsMenu () for chamado.

CommonsWare
fonte
2
Tentei a opção nº 1 e funcionou. Como eu estava tentando atualizar a interface do usuário em um retorno de chamada de um thread separado, estava lançando uma exceção, pois eu não estava realmente no thread da interface do usuário. Para corrigir isso, criei um Handler e enviei uma mensagem de atualização para ele quando meu retorno de chamada foi chamado. Mas, no final das contas, usei getActivity (). InvalidateOptionsMenu () para atualizar o menu.
brockoli
@brockoli: Ah, que bom! Dado o fraseado dos Javadocs para esse método, eu estava cético de que teria o efeito desejado, embora pareça que foi o motivo pelo qual eles o adicionaram ao API Nível 11 em primeiro lugar. Fico feliz em saber que está funcionando para você!
CommonsWare
Eu tenho batido minha cabeça contra a parede tentando descobrir isso e funciona como um encanto!
MinceMan
7
Se você estiver usando a biblioteca de suporte, utilize supportInvalidateOptionsMenu()vez
Tim Kist
2
@TimKist, supportInvalidateOptionsMenu()agora está obsoleto; você pode usar com segurança invalidateOptionsMenu().
Primož Kralj
12

no meu caso: invalidateOptionsMenuapenas restabeleci o texto ao original, mas acessar diretamente o item do menu e reescrever o texto desejado funcionou sem problemas:

if (mnuTopMenuActionBar_ != null) {
    MenuItem mnuPageIndex = mnuTopMenuActionBar_
        .findItem(R.id.menu_magazin_pageOfPage_text);

    if (mnuPageIndex != null) {
        if (getScreenOrientation() == 1) {
            mnuPageIndex.setTitle((i + 1) + " von " + pages);
        }
        else {
            mnuPageIndex.setTitle(
                (i + 1) + " + " + (i + 2) + " " + " von " + pages);
        }
        // invalidateOptionsMenu();
    }
}

devido ao comentário abaixo, consegui acessar o item do menu por meio do seguinte código:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.magazine_swipe_activity, menu);
    mnuTopMenuActionBar_ = menu;
    return true;
}
cV2
fonte
Como você conseguiu um identificador para a visualização ActionBar com mnuTopMenuActionBar_?
Paul Mennega
1
quando a barra de ação é inicializada, salvei a visualização em uma variável de membro ... assim: @Override public boolean onCreateOptionsMenu (Menu menu) {MenuInflater inflater = getMenuInflater (); inflater.inflate (R.menu.magazine_swipe_activity, menu); mnuTopMenuActionBar_ = menu; return true; }
cV2
Ao fazer isso, você pode ter problemas de sincronização, certo? Quero dizer. você não sabe EXATAMENTE quando onCreateOptionMenu será executado, então você pode chegar ao seu trecho de código com o mnuTopMenuActionBar_não inicializado, certo? Como você resolveria isso?
acrespo de
ei, se a barra de ação for usada (sim, aqui está) este método é sempre chamado, então não há problema com isso ... (diretamente no início da atividade) stackoverflow.com/questions/7705927/…
cV2
11

Para atualizar o menu do Fragment, basta chamar:

getActivity().invalidateOptionsMenu();
CoolMind
fonte
4

Eu usei este código:

public boolean onPrepareOptionsMenu (Menu menu) {       
    MenuInflater inflater = getMenuInflater();
    TextView title  = (TextView) findViewById(R.id.title);
    menu.getItem(0).setTitle(
        getString(R.string.payFor) + " " + title.getText().toString());
    menu.getItem(1).setTitle(getString(R.string.payFor) + "...");
    return true;        
}

E funcionou perfeitamente para mim, você pode encontrar OnPrepareOptionsMenu aqui

PERGUNTE
fonte
4
Qual é o objetivo do MenuInflater aqui?
IgorGanapolsky
Isso é brilhante
Steve Kamau
2

Primeiro, siga as duas linhas de código para atualizar os itens da barra de ação antes de definir uma condição em oncreateOptionMenu (). Por exemplo:

Boolean mISQuizItemSelected = false;

/**
 * Called to inflate the action bar menus
 *
 * @param menu
 *      the menu
 *
 * @return true, if successful
 */

@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu items for use in the action bar

    inflater.inflate(R.menu.menu_demo, menu);

    //condition to hide the menus
    if (mISQuizItemSelected) {
        for (int i = 0; i < menu.size(); i++) {
            menu.getItem(i).setVisible(false);
        }
    }

    return super.onCreateOptionsMenu(menu);
}

/**
 * Called when the item on the action bar being selected.
 *
 * @param item
 *      menuitem being selected
 *
 * @return true if the menuitem id being selected is matched
 * false if none of the menuitems id are matched
 */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getId() == R.id.action_quiz) {
        //to navigate based on the usertype either learner or leo
        mISQuizItemSelected = true;

        ActionBar actionBar = getActionBar();
        invalidateOptionMenu();
    }
}
Saranya
fonte
1

Para maior clareza, pensei que um exemplo direto de como agarrar um recurso pode ser mostrado a seguir, que acho que contribui para a resposta a esta pergunta com um exemplo direto rápido.

private MenuItem menuItem_;

@Override
public boolean onCreateOptionsMenu(Menu menuF) 
{
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_layout, menuF);
    menuItem_ = menuF.findItem(R.id.menu_item_identifier);
    return true;
}

Nesse caso, você mantém uma referência MenuItem no início e, em seguida, altera o estado dela (para alterações de estado do ícone, por exemplo) em um determinado momento posterior.

Jay Snayder
fonte
-1

No Kotlin 1.2, basta chamar:

invalidateOptionsMenu()

e a onCreateOptionsMenufunção será chamada novamente.

j_gonfer
fonte