web-dev-qa-db-ja.com

Android BottomNavigationViewで選択項目を設定します

サポートライブラリの新しいAndroid.support.design.widget.BottomNavigationViewを使用しています。コードから現在の選択内容を設定する方法を教えてください。画面を回転させた後、選択が最初の項目に戻ることに気づきました。もちろん、BottomNavigationView関数の現在のonPauseの状態を「保存」する方法、およびonResumeに復元する方法も教えてください。

ありがとうございます。

81
Michael

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

2
Michael

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

BottomNavigationViewが対応するコードの動作を実行できるように、setSelectedItemIdを呼び出す前に、MUSTすべての項目がメニューに追加され、Listenerが設定されていることメニュー項目を追加してリスナーを設定する前にsetSelectedItemIdを呼び出しても何も起こりません。

121
Ricardo

プログラムでBottomNavigationBar項目をクリックするには、次のものを使用する必要があります。

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

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

44
karenms

まだ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を使用して再生し、適切な解決策を見つけることができたと思います。

41
Viacheslav

25.3.0以降のバージョンでsetSelectedItemId()\o /を呼び出すことが可能になりました

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

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

action_item1はメニュー項目IDです。

6
Ashwini

BottomNavigationMenu ItemsにAndroid:enabled="true"を追加します。

そしてbottomNavigationView.setOnNavigationItemSelectedListener(mListener)を設定し、bottomNavigationView.selectedItemId = R.id.your_menu_idを実行して選択したものに設定します。

4

これはおそらく今後のアップデートで追加される予定です。しかしその間に、これを達成するためにはリフレクションを使うことができます。

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
cpienovi

API 25より上ではsetSelectedItemId(menu_item_id)を使用できますが、API 25ではユーザーメニューを別の方法で処理し、setCheckedをChecked特定の項目にする必要があります

3
mhheydarchi

選択的にプログラム的に実行するための別の方法を追加するだけです - これはおそらくそもそも意図していたものであるか、または後で追加されたのかもしれません。

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

performIdentifierActionMenu項目IDとフラグを取ります。

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

2
Darwind

私はあなたのコードを修正したくないのです。もしそうなら、試してみることをお勧めします BottomNavigationViewEx

代わりにメソッドsetCurrentItem(index);getCurrentItem()を呼び出します。

Click here to view the image

2
ittianyu

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

NavigationViewには、似たような問題があるようです。新しいsetCheckedItem()メソッドを追加することで解決しました。

1
Johan Paul

PerformClickメソッドを試すことができます。

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

フラグメントの引数を動的に渡す必要がある場合

ここには多くの(ほとんど繰り返されるか古い)答えがありますが、どれも非常に一般的なニーズを処理しません:タブにロードされたフラグメントに異なる引数を動的に渡す

静的なOnNavigationItemSelectedListenerを呼び出すsetSelectedItemId(R.id.second_tab)を使用して、ロードされたフラグメントに異なる引数を動的に渡すことはできません。この制限を克服するために、タブを含む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
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
Alexey