Setel item yang dipilih di Android BottomNavigationView

123

Saya menggunakan yang baru android.support.design.widget.BottomNavigationViewdari pustaka dukungan. Bagaimana cara mengatur pilihan saat ini dari kode? Saya menyadari, bahwa pemilihan diubah kembali ke item pertama, setelah layar diputar. Tentu saja ini juga akan membantu, jika seseorang dapat memberi tahu saya, bagaimana cara "menyimpan" status saat ini BottomNavigationViewdalam onPausefungsi tersebut dan cara memulihkannya onResume.

Terima kasih!

Michael
sumber
1
Saya baru saja melihat sumbernya dan saya memiliki pertanyaan yang sama .. Sepertinya tidak ada metode untuk menyetel item yang dipilih, dan BottomNavigationViewtidak melakukan penyimpanan internal negara. Mungkin berharap ini disertakan dalam pembaruan di masa mendatang. Gandakan (dengan beberapa info lebih lanjut) di sini: stackoverflow.com/questions/40236786/…
Tim Malseed

Jawaban:

171

Dari API 25.3.0 diperkenalkan metode setSelectedItemId(int id)yang memungkinkan Anda menandai item sebagai dipilih seolah-olah telah disadap.

Dari dokumen:

Setel ID item menu yang dipilih. Ini berperilaku sama seperti mengetuk item.

Contoh kode:

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

PENTING

Anda HARUS sudah menambahkan semua item ke menu (jika Anda melakukan ini secara terprogram) dan menyetel Listener sebelum memanggil setSelectedItemId (Saya yakin Anda ingin kode di listener Anda dijalankan saat memanggil metode ini). Jika Anda memanggil setSelectedItemId sebelum menambahkan item menu dan menyetel listener, tidak akan ada yang terjadi.

Ricardo
sumber
3
Ini TIDAK BEKERJA, ini hanya memperbarui tab itu sendiri, itu tidak memicu peristiwa
setOnNavigationItemSelectedListener
1
Jika Anda belum mendefinisikan perilaku dengan onTabSelectedjelas, itu tidak akan melakukan apa-apa. Baca dokumen -> Setel ID item menu yang dipilih. Ini berperilaku sama seperti mengetuk item. Ini dari Pengembang Android
Ricardo
1
Saya sangat menyarankan Anda untuk men-debug dan meninjau kesalahan yang Anda lakukan. Saya telah menerapkan tiga Aplikasi BottomNavigationView dan tidak pernah memiliki masalah dengan metode ini.
Ricardo
@Ricardo Ketika saya menambahkan ini ke fragmen saya, aplikasi macet saat memasukkan ke fragmen itu
Subin Babu
1
Dalam kasus saya tidak berfungsi, karena saya membuat navigationMenu secara terprogram. Selama konstruksi, klik tidak berfungsi. Setelah semua item ditambahkan ke menu, memanggil setSelectedItemId () berfungsi.
Pedro Romão
53

Untuk mengklik secara terprogram pada item BottomNavigationBar, Anda perlu menggunakan:

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

Ini mengatur semua item dengan labelnya dengan benar.

dianakarenms.dll
sumber
4
Ini adalah peretasan terkait masalah tersebut. Anda memiliki metode dari pustaka itu sendiri yang memungkinkan Anda melakukan apa yang Anda butuhkan. Jika Anda tidak bisa maka itu karena Anda melakukannya salah
Ricardo
47

Bagi mereka yang masih menggunakan SupportLibrary <25.3.0

Saya tidak yakin apakah ini adalah jawaban lengkap untuk pertanyaan ini, tetapi masalah saya sangat mirip - saya harus memproses backpenekanan tombol dan membawa pengguna ke tab sebelumnya di mana dia berada. Jadi, mungkin solusi saya akan berguna untuk seseorang:

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

Harap diingat bahwa jika pengguna menekan tab navigasi lain BottomNavigationViewtidak akan menghapus item yang saat ini dipilih, jadi Anda perlu memanggil metode ini dalam Anda onNavigationItemSelectedsetelah memproses tindakan navigasi:

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

Mengenai penyimpanan status instance, saya pikir Anda dapat bermain dengan action idtampilan navigasi yang sama dan menemukan solusi yang sesuai.

Viacheslav
sumber
Tidak Menu menu = bottomNavigationView.getMenu();mengembalikan salinan menu, jadi bottomNavigationViewobjek tidak terpengaruh?
最 白 目
1
@dan Menurut sumber itu mengembalikan atribut kelas mMenu, bukan salinan android.googlesource.com/platform/frameworks/support/+/master/…
Viacheslav
6
Anda tidak perlu menghapus centang pada item lain, setidaknya pada 26.1.0 / 27.1.0
Jemshit Iskenderov
jangan jangan hapus centang, itu akan menyorotnya
djdance
19
bottomNavigationView.setSelectedItemId(R.id.action_item1);

di mana action_item1ID item menu.

Ashwini
sumber
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));
}
Askar Syzdykov
sumber
7

Sekarang dimungkinkan sejak versi 25.3.0 untuk memanggil setSelectedItemId()\ o /

Nak
sumber
5

Tambahkan android:enabled="true"ke Item BottomNavigationMenu.

Dan kemudian atur bottomNavigationView.setOnNavigationItemSelectedListener(mListener)dan atur sebagai dipilih dengan melakukanbottomNavigationView.selectedItemId = R.id.your_menu_id

Rumaan Khalander
sumber
3

Ini mungkin akan ditambahkan dalam pembaruan yang akan datang. Tetapi sementara itu, untuk mencapai ini Anda bisa menggunakan refleksi.

Buat tampilan kustom yang diperluas dari BottomNavigationView dan akses beberapa bidangnya.

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

}

Dan kemudian gunakan di file layout xml Anda.

<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"/>
cpienovi.dll
sumber
3
Refleksi adalah ide yang buruk!
Filipe Brito
performClick lebih baik daripada refleksi, imho, dalam kasus ini.
Lassi Kinnunen
3

Hanya menambahkan cara lain untuk melakukan seleksi secara terprogram - ini mungkin yang menjadi niat awalnya atau mungkin ini ditambahkan nanti.

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

The performIdentifierActionmengambil Menubarang id dan bendera.

Lihat dokumentasi untuk info lebih lanjut.

Darwind
sumber
Ini tampaknya menjalankan tindakan yang termasuk dalam item menu, tetapi tidak menyebabkan item menu muncul terpilih. Saya pikir yang terakhir adalah yang diinginkan OP, tetapi saya tidak yakin.
LarsH
3

Tampaknya diperbaiki di SupportLibrary 25.1.0 :) Edit: Tampaknya sudah diperbaiki, bahwa status pilihan disimpan, saat memutar layar.

Michael
sumber
1
Saya baru saja memperbarui ke 25.1.1. Masalahnya masih ada.
Xi Wei
3

Di atas API 25 Anda dapat menggunakan setSelectedItemId (menu_item_id) tetapi di bawah API 25 Anda harus melakukan hal yang berbeda, Menu pengguna untuk mendapatkan pegangan dan kemudian setChecked untuk Memeriksa item tertentu

mhheydarchi
sumber
3

Gunakan ini untuk menyetel item menu navigasi bawah yang dipilih berdasarkan id menu

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

Jika Anda tidak ingin mengubah kode Anda. Jika demikian, saya merekomendasikan Anda untuk mencoba BottomNavigationViewEx

Anda hanya perlu mengganti panggilan metode setCurrentItem(index);dan getCurrentItem()

Klik di sini untuk melihat gambar

ittianyu
sumber
2

menggunakan

        bottomNavigationView.getMenu().getItem(0).setChecked(true);
behrad
sumber
1

Saya membuat bug ke Google tentang fakta bahwa tidak ada cara yang dapat diandalkan untuk memilih halaman di BottomNavigationView: https://code.google.com/p/android/issues/detail?id=233697

NavigationView tampaknya memiliki masalah serupa, yang mereka perbaiki dengan menambahkan metode setCheckedItem () baru.

Johan Paul
sumber
1

Anda dapat mencoba metode performClick:

View view = bottomNavigationView.findViewById(R.id.YOUR_ACTION);
view.performClick();
ismail alaoui
sumber
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);
    }
}

Satu-satunya 'minus' dari solusi yang digunakan MenuItemImpl, yaitu 'internal' ke perpustakaan (meskipun publik).

Alexey
sumber
0

JIKA ANDA PERLU SECARA DINAMIS MELALUI ARGUMEN Fragmen LAKUKAN INI

Ada banyak jawaban (kebanyakan berulang atau kedaluwarsa) di sini tetapi tidak ada yang menangani kebutuhan yang sangat umum: meneruskan argumen berbeda secara dinamis ke Fragmen yang dimuat ke tab .

Anda tidak dapat secara dinamis meneruskan argumen yang berbeda ke Fragmen yang dimuat dengan menggunakan setSelectedItemId(R.id.second_tab), yang akhirnya memanggil statis OnNavigationItemSelectedListener. Untuk mengatasi batasan ini saya akhirnya melakukan ini di saya MainActivityyang berisi tab:

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

The ArticleFragment.newInstance()Metode diimplementasikan seperti biasa:

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

}
Albert Vila Calvo
sumber
0

saya harap ini membantu

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

Ini lebih menentukan fragmen default yang dimuat pada saat yang sama dengan item menu navigasi bawah yang sesuai. Anda dapat menyertakan hal yang sama dalam callback OnResume Anda

Zephania Mwando
sumber
0

Metode ini berhasil untuk saya.

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

Contoh

 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()
    }
code4rox
sumber
-1

Refleksi adalah ide yang buruk.

Kepala ke inti ini . Ada metode yang melakukan pemilihan tetapi juga memanggil callback:

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

    }
Nikola Despotoski
sumber
Saya menggunakan callOnClick()alih-alih performClick(), dengan cara ini saya tidak perlu menonaktifkan suara, yang performClick()toh tidak berfungsi .
arekolek