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!
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.
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.
Have you tried this:
invalidateOptionsMenu()
whenever you toggle the nav drawer, by measuring the sliding offset.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.
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.
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.
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
.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With