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!


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.


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.


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.


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.


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

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


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


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"/>

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.


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.


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


3

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

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

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


2

menggunakan

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


1

Anda dapat mencoba metode 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);
    }
}

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


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

}

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


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

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

    }

Saya menggunakan callOnClick()alih-alih performClick(), dengan cara ini saya tidak perlu menonaktifkan suara, yang performClick()toh tidak berfungsi .
arekolek
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.