web-dev-qa-db-ja.com

Navigation Drawerが任意の量だけスライドしたときにActionBar MenuItemsを非表示にする

引き出しを開くたびにActionBarのメニュー項目を非表示にするナビゲーション引き出しを実装しようとしています。

私はグーグルのドキュメントに従っていますが、それらのコードは期待される動作を生成しません。

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

このコードを使用すると、引き出しが完全に開いたときにメニュー項目が非表示になり、引き出しが完全に閉じたときに表示されます。

ただし、Gmailアプリの動作は異なります。メニュー項目は、引き出しが開くとすぐに非表示になります。これは私が望む動作です。誰もこれを達成する方法を知っていますか?

ありがとう!

29
Synergy807

これを試しましたか:

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

ナビゲーションドロワーがスライドした量の検出:

     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はクラスフィールドです。

47

ドロワーが画面に入ってアクションバーを復元するとすぐにアクションバーをオーバーライドし、ドロワーが表示されなくなった瞬間(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);
_

XMLレイアウトで指定した内容に応じて、代わりに_GravityCompat.END_を使用することもできます。

編集-アクションについて

上記の例では、ナビゲーションドロワーの下のコンテンツに関連するアクションバー項目は非表示になりません。これを行うか、ドロワーが表示されているときに異なるアイコンセットを表示するには、ドロワーが手動で開かれたか閉じられたかを追跡する必要があります。

上記のコードに加えて、適切な保存/復元状態処理で_private boolean mDrawerVisible = false_を宣言します。次に、mDrawerToggle内部メソッドを次のように変更します。

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

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

最後に、onCreateOptionsMenuで異なるメニューリソースを膨らませるか、onPrepareOptionsMenumDrawerVisibleの値に基づいて異なるアクションを表示/非表示にします。

5
Eugen Pechanec

私はニコラに半分同意しますが、引き出しの状態が変わったときにアイコンを更新するだけで十分です

引き出しの状態を追跡するグローバル変数を作成します。

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

この質問にはより良い解決策があります:

@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

私は異なるコードを持っていますが、同じ解決策があります:

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

@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に関連付けられたビューにlayout_gravityはXMLでstartに設定されます。
  • OPの質問とは関係ありませんが、迷惑です:引き出しが途中でスタックする原因となる何らかのバグがあるようです。この動作を確認した場合の解決策は次のとおりです。 サンプルを使用したAndroid Navigation Drawerのバグ
0
Vasiliy

すべてのメニュー項目を非表示にする場合は、単に次を使用します。

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

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

次に、各メニュー項目を表示する必要はありません。

0
Cloudream