Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide ActionBar MenuItems when Navigation Drawer slides for any amount

I'm trying to implement a Navigation Drawer that hides the menu items in the ActionBar whenever the drawer is opened.

I am following google's documentation, however their code does not produce the expected behavior.

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

Using this code, the menu items are hidden when the drawer becomes completely opened , and shown when the drawer becomes completely closed.

However, the Gmail app behaves differently. The menu items are hidden as soon as the drawer opens by any amount. This is the behavior I want. Does anyone know how to achieve this?

Thanks!

like image 549
Synergy807 Avatar asked Aug 08 '13 20:08

Synergy807


People also ask

How to set navigation drawer in android?

To add a navigation drawer, first declare a DrawerLayout as the root view. Inside the DrawerLayout , add a layout for the main UI content and another view that contains the contents of the navigation drawer.

What is the drawer menu?

Android Navigation Drawer is a sliding left menu that is used to display the important links in the application. Navigation drawer makes it easy to navigate to and fro between those links. It's not visible by default and it needs to opened either by sliding from left or clicking its icon in the ActionBar.


3 Answers

Have you tried this:

  1. Use invalidateOptionsMenu() whenever you toggle the nav drawer, by measuring the sliding offset.
  2. Iterate over each menu item in onPrepareOptionsMenu(Menu menu) and hide it.

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

Detecting how much the nav drawer has slided:

     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

        }});

Note: shouldGoInvisible is class field.

like image 82
14 revs, 3 users 89% Avatar answered Nov 16 '22 13:11

14 revs, 3 users 89%


If you want to override action bar as soon as drawer enters screen and restore action bar the moment drawer is no longer visible (exactly how Gmail behaves as of March 20, 2014) you can use the following code:

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

Modify restoreActionBar() and overrideActionBar() methods acording to your needs.

There is no need to distinguish between swipes and home button and no need to measure swipe lengths.

Variation

If you don't want to reference the drawer list view use the following code instead:

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

You may want to use GravityCompat.END instead depending on what you specified in XML layout.

Edit - concerning actions

The above example does not hide action bar items relevant to content below the navigation drawer. To do so or show different set of icons when drawer is visible you have to keep track of whether the drawer is opened or closed manually.

In addition to the above code declare private boolean mDrawerVisible = false with proper save/restore state handling. Then modify mDrawerToggle inner methods as follows:

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

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

Finally in onCreateOptionsMenu inflate different menu resource or in onPrepareOptionsMenu show/hide different actions based on the value of mDrawerVisible.

like image 35
Eugen Pechanec Avatar answered Nov 16 '22 12:11

Eugen Pechanec


I'd half agree with Nikola but it's sufficient just to update the icons when the drawer state has

Create a global variable to keep track of the drawer state:

private int mDrawerState;

Set a new 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
  }
});

Update the menu visibility:

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);
}
like image 2
Ljdawson Avatar answered Nov 16 '22 13:11

Ljdawson