Comment mettre à jour un élément de menu affiché dans l'ActionBar?

93

J'ai une activité qui a 2 fragments. Les deux sont des ListFragments et contribuent tous les deux MenuItems au Menu. J'ai un MenuItem pour lequel j'ai défini l'attribut android: showAsAction pour qu'il s'affiche sous forme de bouton sur l'ActionBar. Ce qui fonctionne bien.

Désormais, le MenuItem dépend de l'état. C'est une option de menu Pause / Reprise pour mettre en pause et reprendre une file d'attente. Mon problème est que je ne peux pas comprendre comment définir sa statue initiale lorsque le fragment est créé.

Son état dépend du fait que la file d'attente soit mise en pause ou non. J'ai donc une AsyncTask qui récupère la file d'attente et définit un booléen (mis en pause) en fonction de l'état de la file d'attente. J'appelle onPrepareOptionsMenu pour définir le texte de l'élément de menu Pause en fonction du dernier état connu de la file d'attente et cela fonctionne très bien si je laisse le MenuItem dans le menu réel. Vous appuyez sur l'icône de menu et onPrepareOptionsMenu est déclenché et le menu est mis à jour avant d'être affiché.

Le problème est que si je mets ce même MenuItem sur l'ActionBar (showAsAction), comment puis-je le forcer à se mettre à jour sans avoir à appeler onPrepareOptionsMenu? Je dois pouvoir le faire car au premier lancement de l'application, j'envoie une demande pour obtenir la file d'attente, mais la tâche revient après la configuration et l'affichage de l'ActionBar. J'ai créé un gestionnaire dans mon fragment qui est appelé chaque fois que je reçois une mise à jour de file d'attente, mais à partir de là, comment puis-je mettre à jour le texte de mon MenuItem sur l'ActionBar? Je n'arrive pas à trouver un moyen d'obtenir le menu actuellement défini pour le manipuler, sauf dans onPrepareOptionMenu.

Rob W.

Brockoli
la source

Réponses:

174

Option n ° 1: essayez invalidateOptionsMenu(). Je ne sais pas si cela va forcer un redessiner immédiat de la barre d'action ou non.

Option 2: voir si getActionView()renvoie quelque chose pour les personnes concernées MenuItem. Il est possible que cela showAsActioncrée simplement automatiquement des vues d'action pour vous. Si tel est le cas, vous pouvez vraisemblablement activer / désactiver cela View.

Je n'arrive pas à trouver un moyen d'obtenir le menu actuellement défini pour le manipuler, sauf dans onPrepareOptionMenu.

Vous pouvez vous accrocher à l' Menuobjet qui vous a été remis onCreateOptionsMenu(). Citant les documents :

Vous pouvez en toute sécurité maintenir le menu (et tous les éléments créés à partir de celui-ci), en y apportant les modifications souhaitées, jusqu'à ce que la prochaine fois que onCreateOptionsMenu () soit appelé.

CommonsWare
la source
2
J'ai essayé l'option n ° 1 et cela a fait l'affaire. Puisque j'essayais de mettre à jour l'interface utilisateur dans un rappel à partir d'un thread séparé, cela lançait une exception car je n'étais pas réellement sur le thread de l'interface utilisateur. Pour résoudre ce problème, j'ai créé un gestionnaire et envoyé un message d'actualisation au gestionnaire lorsque mon rappel a été appelé. Mais finalement, j'ai utilisé getActivity (). InvalidateOptionsMenu () pour actualiser le menu.
brockoli
@brockoli: Ah, bien! Compte tenu de la formulation des Javadocs pour cette méthode, j'étais sceptique sur le fait que cela aurait l'effet souhaité, bien qu'il semble que ce soit la raison pour laquelle ils l'ont ajouté au niveau d'API 11 en premier lieu. Heureux d'entendre que cela fonctionne pour vous!
CommonsWare
Je me suis cogné la tête contre le mur en essayant de comprendre cela et cela fonctionne comme un charme!
MinceMan
7
Si vous utilisez la bibliothèque de support, utilisez à la supportInvalidateOptionsMenu()place
Tim Kist
2
@TimKist, supportInvalidateOptionsMenu()est désormais obsolète; vous pouvez utiliser en toute sécurité invalidateOptionsMenu().
Primož Kralj
12

dans mon cas: il invalidateOptionsMenusuffit de reconfigurer le texte sur l'original, mais accéder directement à l'élément de menu et réécrire le texte souhaité a fonctionné sans problème:

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

grâce au commentaire ci-dessous, j'ai pu accéder à l'élément de menu via le code suivant:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.magazine_swipe_activity, menu);
    mnuTopMenuActionBar_ = menu;
    return true;
}
cV2
la source
Comment avez-vous pris connaissance de la vue ActionBar avec mnuTopMenuActionBar_?
Paul Mennega
1
lorsque la barre d'action est initialisée, j'ai enregistré la vue dans une variable membre ... comme ceci: @Override public boolean onCreateOptionsMenu (menu menu) {MenuInflater inflater = getMenuInflater (); inflater.inflate (R.menu.magazine_swipe_activity, menu); mnuTopMenuActionBar_ = menu; retourne vrai; }
cV2
En faisant cela, vous pouvez avoir des problèmes de synchronisation, n'est-ce pas? Je veux dire. vous ne savez pas exactement quand onCreateOptionMenu va s'exécuter, vous pouvez donc atteindre votre morceau de code avec le mnuTopMenuActionBar_non initialisé, non? Comment contourneriez-vous cela?
acrespo
hé, si la barre d'action est utilisée (oui, c'est ici) cette méthode est toujours appelée, donc il n'y a pas de problème avec ça ... (directement au démarrage de l'activité) stackoverflow.com/questions/7705927
...
11

Pour actualiser le menu à partir de Fragment, appelez simplement:

getActivity().invalidateOptionsMenu();
CoolMind
la source
4

J'ai utilisé ce code:

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

Et a fonctionné comme un charme pour moi, vous pouvez trouver OnPrepareOptionsMenu ici

DEMANDER
la source
4
Quel est le but de MenuInflater ici?
IgorGanapolsky
C'est brillant
Steve Kamau
2

Veuillez d'abord suivre les deux lignes de codes pour mettre à jour les éléments de la barre d'action avant de définir une condition dans oncreateOptionMenu (). Par exemple:

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

Pour plus de clarté, j'ai pensé qu'un exemple direct de saisie sur une ressource peut être montré à partir de ce qui suit qui, je pense, contribue à la réponse à cette question avec un exemple direct rapide.

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

Dans ce cas, vous maintenez une référence MenuItem au début, puis changez son état (pour les changements d'état d'icône par exemple) à un moment donné plus tard.

Jay Snayder
la source
-1

Dans Kotlin 1.2, appelez simplement:

invalidateOptionsMenu()

et la onCreateOptionsMenufonction sera à nouveau appelée.

j_gonfer
la source