Android BottomNavigationViewで選択したアイテムを設定する


123

android.support.design.widget.BottomNavigationViewサポートライブラリの新しいものを使用しています。コードから現在の選択を設定するにはどうすればよいですか?画面を回転させた後、選択が最初のアイテムに戻ることに気付きました。もちろん、それは助けも希望、誰かが私に言うことができれば、どのように現在の状態「保存」BottomNavigationViewonPause機能し、それを復元する方法onResume

ありがとう!


1
ソースを確認したばかりで、同じ質問があります。選択したアイテムを設定する方法BottomNavigationViewはないようで、状態の内部保存は行いません。おそらくこれが将来のアップデートに含まれることを期待しています。(いくつかのより多くの情報を持つ)重複こちら:stackoverflow.com/questions/40236786/...
ティムMalseed

回答:


170

API 25.3.0からsetSelectedItemId(int id)、アイテムがタップされたかのように選択済みとしてマークできるメソッドが導入されました。

ドキュメントから:

選択したメニューアイテムIDを設定します。これは、アイテムをタップするのと同じように動作します。

コード例:

BottomNavigationView bottomNavigationView;
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(myNavigationItemListener);
bottomNavigationView.setSelectedItemId(R.id.my_menu_item_id);

重要

メニューにすべての項目を追加して(プログラムでこれを行う場合)、setSelectedItemIdを呼び出す前にリスナーを設定しておく必要があります(このメソッドを呼び出すときにリスナーのコードを実行する必要があると思います)。メニュー項目を追加してリスナーを設定する前にsetSelectedItemIdを呼び出すと、何も起こりません。


3
これは機能せず、タブ自体を更新するだけで、setOnNavigationItemSelectedListenerイベントをトリガーしません
TjerkW

1
で動作を定義していない場合、onTabSelected明らかに何もしません。ドキュメントを読む->選択したメニュー項目IDを設定します。これは、アイテムをタップするのと同じように動作します。Android開発者による
Ricardo

1
私はあなたが間違っていることをデバッグしてレビューすることを強くお勧めします。私はすでに3つのBottomNavigationViewアプリケーションを実装しており、このメソッドで問題が発生したことはありません。
Ricardo

@Ricardoこれをフラグメントに追加すると、そのフラグメントに入るときにアプリケーションがハングしました
Subin Babu

1
私の場合、navigationMenuをプログラムで作成していたため、機能しませんでした。構築中、クリックは機能しませんでした。すべてのアイテムがメニューに追加された後、setSelectedItemId()の呼び出しが機能しました。
PedroRomão2018

53

プログラムでBottomNavigationBarアイテムをクリックする必要がある場合は、以下を使用します。

View view = bottomNavigationView.findViewById(R.id.menu_action_item);
view.performClick();

これにより、すべてのアイテムがラベル付きで正しく配置されます。


4
これは問題に関するハックです。必要なことを実行できるライブラリ自体のメソッドがあります。それができない場合、それはあなたが間違っているからです
Ricardo

47

SupportLibrary <25.3.0をまだ使用しているユーザー向け

これがこの質問に対する完全な回答であるかどうかはわかりませんが、私の問題は非常に似ていました。backボタンを押して、ユーザーを以前のタブに移動する必要がありました。だから、多分私の解決策は誰かにとって役に立つでしょう:

private void updateNavigationBarState(int actionId){
    Menu menu = bottomNavigationView.getMenu();

    for (int i = 0, size = menu.size(); i < size; i++) {
        MenuItem item = menu.getItem(i);
        item.setChecked(item.getItemId() == actionId);
    }
}

ユーザーが他のナビゲーションタブBottomNavigationViewを押した場合、現在選択されている項目がクリアされないためonNavigationItemSelected、ナビゲーションアクションの後処理でこのメソッドを呼び出す必要があることに注意してください。

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()) {
        case R.id.some_id_1:
            // process action
            break;
        case R.id.some_id_2:
            // process action
            break;
        ...
        default:
            return false;
    }

    updateNavigationBarState(item.getItemId());

    return true;
}

インスタンス状態の保存についてはaction id、ナビゲーションビューと同じように遊んで適切な解決策を見つけることができると思います。


Doesn't Menu menu = bottomNavigationView.getMenu();ので、メニューのコピーを返すbottomNavigationViewオブジェクトは影響を受けませんか?
最白目

1
ソースによると@danそれはコピー、クラス属性mMenuを返しませんandroid.googlesource.com/platform/frameworks/support/+/master/...
Viacheslav

6
少なくとも26.1.0 / 27.1.0では、他のアイテムのチェックを外す必要はありません
Jemshit Iskenderov

オフにしないでください。ハイライト表示されます
djdance

19
bottomNavigationView.setSelectedItemId(R.id.action_item1);

ここaction_item1で、メニュー項目IDです。


8
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

   bottomNavigationView.setOnNavigationItemSelectedListener(this);
   Menu menu = bottomNavigationView.getMenu();
   this.onNavigationItemSelected(menu.findItem(R.id.action_favorites));
}

7

25.3.0バージョン以降、setSelectedItemId()\ o / を呼び出すことができるようになりました


5

android:enabled="true"BottomNavigationMenuアイテムに追加します。

そして、設定bottomNavigationView.setOnNavigationItemSelectedListener(mListener)してそれを選択して設定しますbottomNavigationView.selectedItemId = R.id.your_menu_id


3

これはおそらく今後のアップデートで追加されるでしょう。しかし、当面は、これを実現するためにリフレクションを使用できます。

BottomNavigationViewから拡張されたカスタムビューを作成し、そのフィールドの一部にアクセスします。

public class SelectableBottomNavigationView extends BottomNavigationView {

    public SelectableBottomNavigationView(Context context) {
        super(context);
    }

    public SelectableBottomNavigationView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SelectableBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setSelected(int index) {
        try {
            Field f = BottomNavigationView.class.getDeclaredField("mMenuView");
            f.setAccessible(true);
            BottomNavigationMenuView menuView = (BottomNavigationMenuView) f.get(this);

            try {
                Method method = menuView.getClass().getDeclaredMethod("activateNewButton", Integer.TYPE);
                method.setAccessible(true);
                method.invoke(menuView, index);
            } catch (SecurityException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

}

そして、それをxmlレイアウトファイルで使用します。

<com.your.app.SelectableBottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:itemBackground="@color/primary"
        app:itemIconTint="@drawable/nav_item_color_state"
        app:itemTextColor="@drawable/nav_item_color_state"
        app:menu="@menu/bottom_navigation_menu"/>

3
反射は悪い考えです!
フィリップブリト

この場合、performClickはリフレクションimhoより優れています。
Lassi Kinnunen、

3

選択をプログラムで実行する別の方法を追加するだけです-これはおそらく最初の意図であったか、おそらく後で追加されました。

Menu bottomNavigationMenu = myBottomNavigationMenu.getMenu();
bottomNavigationMenu.performIdentifierAction(selected_menu_item_id, 0);

performIdentifierActionかかるMenuアイテムIDとフラグ。

詳細については、ドキュメントを参照してください。


これは、メニュー項目に属するアクションを実行しているように見えますが、メニュー項目が選択されているようには見えません。後者はOPが欲しかったものだと思いましたが、私は前向きではありません。
LarsH

3

SupportLibrary 25.1.0で修正されているようです:)編集:画面を回転すると、選択の状態が保存されるように修正されたようです。


1
25.1.1に更新しました。問題はまだそこにあります。
Xi Wei

3

API 25より上ではsetSelectedItemId(menu_item_id)を使用できますが、API 25では、ユーザーメニューを使用してハンドルを取得し、setCheckedをCheckedの特定のアイテムに変更する必要があります。


3

これを使用して、選択した下部ナビゲーションメニュー項目をメニューIDで設定します

MenuItem item = mBottomNavView.getMenu().findItem(menu_id);
item.setChecked(true);

2

コードを変更したくない。その場合は、BottomNavigationViewExを試すことをお勧めします。

あなたは単にメソッドsetCurrentItem(index);を呼び出して置き換える必要がありgetCurrentItem()ます。

ここをクリックして画像を表示


2

使用する

        bottomNavigationView.getMenu().getItem(0).setChecked(true);

1

BottomNavigationViewでページを選択する信頼できる方法がないという事実について、Googleにバグを報告しました:https ://code.google.com/p/android/issues/detail?id=233697

NavigationViewにも同様の問題があったようですが、新しいsetCheckedItem()メソッドを追加することで修正されました。


1

あなたはperformClickメソッドを試すことができます:

View view = bottomNavigationView.findViewById(R.id.YOUR_ACTION);
view.performClick();

0
private void setSelectedItem(int actionId) {
    Menu menu = viewBottom.getMenu();
    for (int i = 0, size = menu.size(); i < size; i++) {
        MenuItem menuItem = menu.getItem(i);
        ((MenuItemImpl) menuItem).setExclusiveCheckable(false);
        menuItem.setChecked(menuItem.getItemId() == actionId);
        ((MenuItemImpl) menuItem).setExclusiveCheckable(true);
    }
}

ソリューションの唯一の「マイナス」は、MenuItemImpl(パブリックではありますが)ライブラリの「内部」であるを使用することです。


0

フラグメント引数を動的に渡す必要がある場合は、これを実行してください

ここにはたくさんの(ほとんど繰り返された、または時代遅れの)回答がありますが、どれも非常に一般的なニーズに対応していません:動的に異なる引数をタブにロードされたフラグメントに渡すです。

setSelectedItemId(R.id.second_tab)staticを呼び出すことになるを使用して、読み込まれたFragmentに異なる引数を動的に渡すことはできませんOnNavigationItemSelectedListener。この制限を克服するために、私MainActivityはタブを含む私の中でこれをやった:

fun loadArticleTab(articleId: String) {
    bottomNavigationView.menu.findItem(R.id.tab_article).isChecked = true // use setChecked() in Java
    supportFragmentManager
        .beginTransaction()
        .replace(R.id.main_fragment_container, ArticleFragment.newInstance(articleId))
        .commit()
}

ArticleFragment.newInstance()この方法は、いつものように実装されます。

private const val ARG_ARTICLE_ID = "ARG_ARTICLE_ID"

class ArticleFragment : Fragment() {

    companion object {
        /**
         * @return An [ArticleFragment] that shows the article with the given ID.
         */
        fun newInstance(articleId: String): ArticleFragment {
            val args = Bundle()
            args.putString(ARG_ARTICLE_ID, day)
            val fragment = ArticleFragment()
            fragment.arguments = args
            return fragment
        }
    }

}

0

これが役に立てば幸い

//Setting default selected menu item and fragment
        bottomNavigationView.setSelectedItemId(R.id.action_home);
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.fragment_container, new HomeFragment()).commit();

これは、対応する下部のナビゲーションメニュー項目と同時にロードされるデフォルトのフラグメントを決定するためのものです。OnResumeコールバックに同じものを含めることができます


0

この方法でうまくいきます。

private fun selectBottomNavigationViewMenuItem(bottomNavigationView : BottomNavigationView,@IdRes menuItemId: Int) {
            bottomNavigationView.setOnNavigationItemSelectedListener(null)
            bottomNavigationView.selectedItemId = menuItemId
            bottomNavigationView.setOnNavigationItemSelectedListener(this)
        }

 override fun onBackPressed() {
        replaceFragment(HomeFragment())
        selectBottomNavigationViewMenuItem(navView, R.id.navigation_home)
    }



private fun replaceFragment(fragment: Fragment) {
        val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
        transaction.replace(R.id.frame_container, fragment)
        transaction.commit()
    }

-1

反射は悪い考えです。

この要点に向かいます。選択を実行するだけでなく、コールバックを呼び出すメソッドがあります。

  @CallSuper
    public void setSelectedItem(int position) {
        if (position >= getMenu().size() || position < 0) return;

        View menuItemView = getMenuItemView(position);
        if (menuItemView == null) return;
        MenuItemImpl itemData = ((MenuView.ItemView) menuItemView).getItemData();


        itemData.setChecked(true);

        boolean previousHapticFeedbackEnabled = menuItemView.isHapticFeedbackEnabled();
        menuItemView.setSoundEffectsEnabled(false);
        menuItemView.setHapticFeedbackEnabled(false); //avoid hearing click sounds, disable haptic and restore settings later of that view
        menuItemView.performClick();
        menuItemView.setHapticFeedbackEnabled(previousHapticFeedbackEnabled);
        menuItemView.setSoundEffectsEnabled(true);


        mLastSelection = position;

    }

callOnClick()代わりに使用しますperformClick()。これにより、サウンドを無効にする必要がなくなりperformClick()ます。これは、とにかく機能しませんでした。
arekolek 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.