web-dev-qa-db-fra.com

Comment actualiser le ActionBar lorsque onPrepareOptionsMenu a changé de menu?

Dans mes applications, j'active souvent/désactive les entrées de menu et les rend visibles depuis onPrepareOptionsMenu.

Aujourd'hui, j'ai commencé à ajouter l'attribut de menu Android: showAsAction à certaines de mes applications Android 2.x pour afficher les entrées de menu les plus utilisées sur le ActionBar.

La barre d'actions ne reflète pas l'activation/désactivation et la visibilité immédiate. Je dois cliquer sur le menu déroulant à droite pour voir ce changement se produire.

Ok, je comprends que le menu se déclenche surPrepareOptionsMenu. Mais que dois-je faire pour actualiser la barre d’action? Je pense que ce changement doit être appliqué de l'intérieur à onOptionsItemSelected mais je ne sais pas comment appeler.

Voilà le menu:

<item
    Android:icon="@drawable/ic_menu_mapmode"
    Android:id="@+id/men_mapview"
    Android:showAsAction="ifRoom|withText"
    Android:title="@string/txt_mapview" />

<item
    Android:icon="@drawable/ic_menu_mapmode"
    Android:id="@+id/men_satelliteview"
    Android:showAsAction="ifRoom|withText"
    Android:title="@string/txt_satelliteview" />

Voici le onPrepareOptionsMenu:

@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
    MenuItem menuItemMapView = menu.findItem(R.id.men_mapview);
    MenuItem menuItemSatelliteView = menu.findItem(R.id.men_satelliteview);

    if (mapView.isSatellite()) {
        menuItemMapView.setEnabled(true).setVisible(true);
        menuItemmenuItemSatelliteView.setEnabled(false).setVisible(false);
    } else {
        menuItemMapView.setEnabled(false).setVisible(false);
        menuItemmenuItemSatelliteView.setEnabled(true).setVisible(true);
    }

    return super.onPrepareOptionsMenu(menu);
}

Voici le onOptionsItemSelected

@Override
public boolean onOptionsItemSelected(final MenuItem menuItem) {
    switch (menuItem.getItemId()) {
        case R.id.men_mapview:
            mapView.setSatellite(false);
            mapView.setStreetView(true);
            mapView.invalidate();

            invalidateOptionsMenu(); // This works on Android 3.x devices only
            return true;
        case R.id.men_satelliteview:
            mapView.setSatellite(true);
            mapView.setStreetView(false);
            mapView.invalidate();

            invalidateOptionsMenu(); // This works on Android 3.x devices only
            return true;
    }

    return super.onOptionsItemSelected(menuItem);
}

EDIT: Si j'ajoute invalidateOptionsMenu, cela fonctionne sur les applications Android 3.x mais se bloque sur les appareils Android 2.x en raison d'une méthode manquante. Quelle est la façon recommandée de bien faire les choses?

56
Harald Wilhelm

Ma méthode de choix consiste à créer une classe d'assistance. Par exemple:

class VersionHelper
{
    static void refreshActionBarMenu(Activity activity)
    {
        activity.invalidateOptionsMenu();
    }
}

Maintenant, dans votre code ci-dessus, remplacez invalidateOptionsMenu(); par:

if (Build.VERSION.SDK_INT >= 11)
{
    VersionHelper.refreshActionBarMenu(this);
}

Le crédit de cette méthode revient à CommonsWare (recherchez HoneycombHelper et consultez ses livres - hautement recommandé)

81
wirbly

Merci à la réponse acceptée. J'utilise ActionBarActivity. dans cette classe, vous pouvez utiliser 

supportInvalidateOptionsMenu();
66
jeremyvillalobos

Utilisation

ActivityCompat.invalidateOptionsMenu(Activity activity)

à partir de la bibliothèque compatibilité .

Voir: https://stackoverflow.com/a/14748687/435855

14
Urizev

enregistrer une référence au menu et appeler:

this.menu.clear();
this.onCreateOptionsMenu(this.menu);
10
Klaasvaak

Vous pouvez maintenant utiliser la méthode supportInvalidateOptionsMenu () à partir de ActionbarActivity avec la bibliothèque de support. Donc, vous n'avez pas à vérifier la version du SDK. Va jusqu'à API 7 et ci-dessus.

http://developer.Android.com/reference/Android/support/v7/app/ActionBarActivity.html

pour ce faire, vous devez importer la v7 de la bibliothèque de support à l'aide de cette

http://developer.Android.com/tools/support-library/setup.html

4
Farfelufrank

Basé sur "Klaasvaak" réponse ci-dessus. J'utilise ses sous-menus. Cela fonctionne pour moi:

// Declare and save the menu as global, so it can be called anywhere.
Menu absTopSubMenus;

public boolean onCreateOptionsMenu(Menu menu) {

absTopSubMenus = menu;  // Used for re-drawing this menu anywhere in the codes.

// The remainder of your code below
}

Ensuite, pour ré-dessiner ceci, appelez simplement:

// Redraw the top sub-menu
absTopSubMenus.clear();
onCreateOptionsMenu(absTopSubMenus);
3
Britc

Je ne suis pas sûr que vous l'ayez déjà vu, mais si vous utilisez abondamment la barre d'actions et prévoyez de prendre en charge les API inférieures (> 8), jetez un coup d'œil à la bibliothèque actionBarSherlock. Cela fera en sorte que vous n'ayez pas à diviser votre code actionBar pour les API inférieure et supérieure, et ensuite vous pourrez simplement exécuter:

runOnUiThread(new Runnable(){
  @Override
  public void run(){
    supportInvalidateOptionsMenu();
  }
});
3
user1528493

getActivity (). invalidateOptionsMenu ();

fait le travail.

2
Karun Shrestha

Félicitations à @Klaasvaak pour nous avoir montré le chemin. J'utilise les éléments suivants, qui fonctionnent à la fois avant et après l'API Level 11:

private void invalidOptionsMenuHelper() {
    if (Build.VERSION.SDK_INT >= 11) {
        invalidateOptionsMenu();

    } else if (mOptionsMenu != null) {
        mOptionsMenu.clear();
        onCreateOptionsMenu(mOptionsMenu);
    }
}

Bien sûr, vous devez enregistrer une référence au menu (mOptionsMenu dans ce cas) que je réalise via:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    mOptionsMenu = menu;

    //... create and manage the menu normally
}
1
Mike Repass

Assurez-vous également que vous n'appelez pas 

myAppCompatActivity.setToolbarTitle("some dynamic title");

peu de temps après avoir rafraîchi votre menu. 

J'ai eu le problème que les tirables ne seraient pas visibles même s'il y avait place pour les afficher. Une fois que j'ai fait un changement d'orientation, les drawables sont alors apparus ..?

En résumé:

Activité principale:

public class MainActivity extends AppCompatActivity {

    private boolean showMenu = true;

    public void setShowMenu(boolean show) {
        showMenu = show;
        supportInvalidateOptionsMenu();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.my_menu, menu);
        menu.findItem(R.id.menu_share).setVisible(showMenu);
        // menu.findItem(...
        return true;
    }
}

FragmentNoMenu:

public abstract class FragmentNoMenu extends Fragment {

    protected MainActivity mainActivity;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        mainActivity = (MainActivity) getActivity();
        if (mainActivity != null) {
            mainActivity.setShowMenu(false);
        }
    }

}

FragmentWithMenu:

public abstract class FragmentWithMenu extends Fragment {

    protected MainActivity mainActivity;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        mainActivity = (MainActivity) getActivity();
        if (mainActivity != null) {
            mainActivity.setShowMenu(true);
        }
    }

}
0
IHeartAndroid