web-dev-qa-db-fra.com

Masquer les éléments du menu de la barre d'action lorsque le tiroir de navigation glisse pour un montant quelconque

J'essaie d'implémenter un tiroir de navigation qui masque les éléments de menu dans l'ActionBar chaque fois que le tiroir est ouvert.

Je suis la documentation de Google, mais leur code ne produit pas le comportement attendu.

http://developer.Android.com/training/implementing-navigation/nav-drawer.html

En utilisant ce code, les éléments de menu sont masqués lorsque le tiroir devient complètement ouvert , et affichés lorsque le tiroir devient complètement fermé.

Cependant, l'application Gmail se comporte différemment. Les éléments du menu sont masqués dès que le tiroir s'ouvre de n'importe quel montant . C'est le comportement que je veux. Personne ne saurais comment achever cela?

Merci!

29
Synergy807

Avez-vous essayé ceci:

  1. Utilisez invalidateOptionsMenu() chaque fois que vous basculez le tiroir de navigation, en mesurant le décalage coulissant.
  2. Parcourez chaque élément de menu dans onPrepareOptionsMenu(Menu menu) et masquez-le.

    @Override
    
    public boolean onPrepareOptionsMenu(Menu menu) {
    
        // If the nav drawer is open, hide action items related to the content view
        boolean drawerOpen = shouldGoInvisible;
        hideMenuItems(menu, !drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
    
    private void hideMenuItems(Menu menu, boolean visible)
    {
    
        for(int i = 0; i < menu.size(); i++){
    
            menu.getItem(i).setVisible(visible);
    
        }
    }
    

Détection de la quantité de glissement du tiroir de navigation:

     mDrawerLayout.setDrawerListener(new DrawerListener(){
                    float mPreviousOffset = 0f;

        @Override
        public void onDrawerClosed(View arg0) {
                         super.onDrawerClosed(arg0);
                         shouldGoInvisible = false;
                         invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
        }

        @Override
        public void onDrawerOpened(View arg0) {
                         super.onDrawerOpened(arg0);
                         shouldGoInvisible = true;
                         invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
        }

        @Override
        public void onDrawerSlide(View arg0, float slideOffset) {
             super.onDrawerSlide(arg0, slideOffset);
             if(slideOffset > mPreviousOffset && !shouldGoInvisible){
                shouldGoInvisible = true;
                invalidateOptionsMenu();
            }else if(mPreviousOffset > slideOffset && slideOffset < 0.5f && shouldGoInvisible){
                shouldGoInvisible = false;
                invalidateOptionsMenu();
            }
            mPreviousOffset = slideOffset;


        }

        @Override
        public void onDrawerStateChanged(int arg0) {
            // or use states of the drawer to hide/show the items

        }});

Remarque: shouldGoInvisible est un champ de classe.

47
Nikola Despotoski

Si vous souhaitez remplacer la barre d'actions dès que le tiroir entre dans l'écran et restaurer la barre d'actions dès que le tiroir n'est plus visible (exactement comment Gmail se comporte au 20 mars 2014), vous pouvez utiliser le code suivant:

mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
    R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {

  @Override
  public void onDrawerStateChanged(int newState) {
    super.onDrawerStateChanged(newState);

    boolean isOpened = mDrawerLayout.isDrawerOpen(mDrawerList);
    boolean isVisible = mDrawerLayout.isDrawerVisible(mDrawerList);

    if (!isOpened && !isVisible) {
      if (newState == DrawerLayout.STATE_IDLE) {
        // drawer just hid completely
        restoreActionBar();
      } else {
        // } else if (newState == DrawerLayout.STATE_SETTLING) {
        // drawer just entered screen
        overrideActionBar();
      }
    }
  }

  private void restoreActionBar() {
    getSupportActionBar().setTitle(mTitle);
    supportInvalidateOptionsMenu();
  }

  private void overrideActionBar() {
    getSupportActionBar().setTitle(mDrawerTitle);
    supportInvalidateOptionsMenu();
  }
};

// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);

Modifiez les méthodes restoreActionBar() et overrideActionBar() selon vos besoins.

Il n'est pas nécessaire de faire la distinction entre les balayages et le bouton d'accueil et il n'est pas nécessaire de mesurer les longueurs de balayage.

Variation

Si vous ne voulez pas référencer la vue de la liste des tiroirs, utilisez plutôt le code suivant:

    boolean isOpened = mDrawerLayout.isDrawerOpen(GravityCompat.START);
    boolean isVisible = mDrawerLayout.isDrawerVisible(GravityCompat.START);

Vous pouvez utiliser à la place GravityCompat.END En fonction de ce que vous avez spécifié dans la disposition XML.

Modifier - concernant les actions

L'exemple ci-dessus ne masque pas les éléments de la barre d'actions relatifs au contenu sous le tiroir de navigation. Pour ce faire ou afficher différents ensembles d'icônes lorsque le tiroir est visible, vous devez savoir si le tiroir est ouvert ou fermé manuellement.

En plus du code ci-dessus, déclarez private boolean mDrawerVisible = false Avec une gestion correcte de l'état de sauvegarde/restauration. Modifiez ensuite les méthodes internes mDrawerToggle comme suit:

  private void restoreActionBar() {
    getSupportActionBar().setTitle(mTitle);
    mDrawerVisible = false;
    supportInvalidateOptionsMenu();
  }

  private void overrideActionBar() {
    getSupportActionBar().setTitle(mDrawerTitle);
    mDrawerVisible = true;
    supportInvalidateOptionsMenu();
  }

Enfin dans onCreateOptionsMenu gonflez différentes ressources de menu ou dans onPrepareOptionsMenu affichez/masquez différentes actions en fonction de la valeur de mDrawerVisible.

5
Eugen Pechanec

Je suis à moitié d'accord avec Nikola, mais il suffit de mettre à jour les icônes lorsque l'état du tiroir a

Créez une variable globale pour suivre l'état du tiroir:

private int mDrawerState;

Définissez un nouveau DrawerListener:

mDrawerLayout.setDrawerListener(new DrawerListener() {

  @Override
  public void onDrawerStateChanged(int state) {
    mDrawerState = state;
    invalidateOptionsMenu();
  }

  @Override
  public void onDrawerSlide(View view, float slide) {
    // TODO Auto-generated method stub
  }

  @Override
  public void onDrawerOpened(View view) {
    // TODO Auto-generated method stub
  }

  @Override
  public void onDrawerClosed(View view) {
    // TODO Auto-generated method stub
  }
});

Mettez à jour la visibilité du menu:

boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawer);
for(int i=0;i<menu.size();i++){
  // If the drawer is moving / settling or open do not draw the icons
  menu.getItem(i).setVisible(mDrawerState!=DrawerLayout.STATE_DRAGGING &&
      mDrawerState!=DrawerLayout.STATE_SETTLING && !drawerOpen);
}
2
Ljdawson

J'ai une meilleure solution pour cette question:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    if (navigationDrawerFragment.isDrawerOpen()) {
        menu.clear();
    }
    return super.onPrepareOptionsMenu(menu);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    if (!navigationDrawerFragment.isDrawerOpen()) {
        // Only show items in the action bar relevant to this screen
        // if the drawer is not showing. Otherwise, let the drawer
        // decide what to show in the action bar.
        showLocalContextActionBar();
        return false;
    }
    return super.onCreateOptionsMenu(menu);
}
1
GFPF

J'ai un code différent mais la même solution:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    hideMenuItems(menu, !mShouldGoInvisible);
    return super.onCreateOptionsMenu(menu);
}
private void hideMenuItems(Menu menu, boolean visible){
    for(int i = 0; i < menu.size(); i++){

        menu.getItem(i).setVisible(visible);
    }
}

et

 @Override
public void onNavigationDrawerListener(boolean opened, int position) {

    if (opened){
        mShouldGoInvisible = true;
        invalidateOptionsMenu();

    } else {
        mShouldGoInvisible = false;
        invalidateOptionsMenu();
    }
}
0
Cabezas

J'ai pris la réponse de @Laurence Dawson et je l'ai simplifiée un peu. Cette solution ne nécessite aucun membre de classe à utiliser.

Exécutez ce code pendant onCreate():

    DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

    drawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() {

        @Override
        public void onDrawerSlide(View view, float v) {
            invalidateOptionsMenu();
        }

        @Override
        public void onDrawerClosed(View view) {
            invalidateOptionsMenu();
        }

        @Override
        public void onDrawerOpened(View view) {}

        @Override
        public void onDrawerStateChanged(int state) {}
    });

Et remplacez cette méthode:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {

    DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    boolean actionsVisibility = !drawerLayout.isDrawerVisible(Gravity.START);

    for(int i=0;i<menu.size();i++){
        menu.getItem(i).setVisible(actionsVisibility);
    }

    return super.onPrepareOptionsMenu(menu);
}

Quelques notes:

  • L'implémentation ci-dessus suppose que la vue associée à NavigationDrawer a son layout_gravity défini sur start en XML.
  • Sans rapport avec la question de OP, mais ennuyeux: il semble y avoir une sorte de bogue qui bloque le tiroir en cours de route. Si vous observez ce comportement, voici la solution: bogue Android Navigation Drawer utilisant l'exemple
0
Vasiliy

Si vous souhaitez masquer tous les éléments du menu, utilisez simplement:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);

    return showActionBarMenu; // boolean value, set it in drawer listeners as class variable
}

Ensuite, vous n'avez pas besoin de voir chaque élément de menu.

0
Cloudream