导航抽屉滑动任何数量时隐藏ActionBar MenuItems

时间:2013-08-08 20:10:37

标签: android actionbarsherlock navigation-drawer

我正在尝试实现一个导航抽屉,只要打开抽屉,它就会隐藏ActionBar中的菜单项。

我正在关注谷歌的文档,但他们的代码不会产生预期的行为。

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

使用此代码,当抽屉完全打开时,菜单项将被隐藏,并在抽屉完全关闭时显示。

但是,Gmail应用的行为有所不同。一旦抽屉以任何数量打开,菜单项就会被隐藏。这是我想要的行为。有谁知道如何实现这个目标?

谢谢!

7 个答案:

答案 0 :(得分:47)

你试过这个:

  1. 每当您通过测量滑动偏移来切换导航抽屉时,请使用invalidateOptionsMenu()
  2. onPrepareOptionsMenu(Menu menu)中的每个菜单项进行迭代并隐藏它。

    @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);
    
        }
    }
    
  3. 检测导航抽屉滑落的程度:

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

    注意:shouldGoInvisible是类字段。

答案 1 :(得分:5)

如果您想在抽屉进入屏幕后立即覆盖操作栏并恢复操作栏,那么当前抽屉不再可见(截至2014年3月20日Gmail的行为方式),您可以使用以下代码:

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

根据您的需要修改restoreActionBar()overrideActionBar()方法。

无需区分滑动和主页按钮,也无需测量滑动长度。

变异

如果您不想引用抽屉列表视图,请改为使用以下代码:

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

您可能希望使用GravityCompat.END,具体取决于您在XML布局中指定的内容。

编辑 - 关于行动

以上示例不会隐藏与导航抽屉下方内容相关的操作栏项。要在抽屉可见时执行此操作或显示不同的图标集,您必须手动跟踪抽屉是打开还是关闭。

除上述代码外,还声明private boolean mDrawerVisible = false具有正确的保存/恢复状态处理。 然后修改mDrawerToggle内部方法,如下所示:

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

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

最后在onCreateOptionsMenu中填充不同的菜单资源或onPrepareOptionsMenu根据mDrawerVisible的值显示/隐藏不同的操作。

答案 2 :(得分:2)

我半数同意Nikola,但只有在抽屉状态出现时更新图标就足够了

创建一个全局变量来跟踪抽屉状态:

private int mDrawerState;

设置一个新的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
  }
});

更新菜单可见性:

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

答案 3 :(得分:1)

我对这个问题有更好的解决方案:

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

答案 4 :(得分:0)

如果要隐藏所有菜单项,只需使用:

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

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

然后您不需要看到每个菜单项。

答案 5 :(得分:0)

我接受了@Laurence Dawson的回答并简化了一下。此解决方案不需要使用任何类成员。

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

并覆盖此方法:

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

很少注意到:

  • 上述实现假定与NavigationDrawer关联的视图在XML中将layout_gravity设置为start
  • 与OP的问题无关,但令人讨厌:似乎有某种错误会导致抽屉卡在路上。如果您确实观察到此行为,请执行以下解决方案:Android Navigation Drawer bug using the sample

答案 6 :(得分:0)

我有不同的代码但是同样的解决方案:

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

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

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

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