Đặt mục đã chọn trong Android BottomNavigationView


123

Tôi đang sử dụng cái mới android.support.design.widget.BottomNavigationViewtừ thư viện hỗ trợ. Làm cách nào để đặt lựa chọn hiện tại từ mã? Tôi nhận ra rằng lựa chọn được thay đổi trở lại mục đầu tiên, sau khi xoay màn hình. Tất nhiên nó cũng sẽ hữu ích, nếu ai đó có thể cho tôi biết, làm thế nào để "lưu" trạng thái hiện tại của hàm BottomNavigationViewtrong onPausevà cách khôi phục nó trong onResume.

Cảm ơn!


1
Tôi vừa xem qua nguồn và tôi có câu hỏi tương tự .. Có vẻ như không có phương pháp nào để đặt mục đã chọn và BottomNavigationViewkhông thực hiện bất kỳ lưu trạng thái nội bộ nào. Có thể mong đợi điều này sẽ được bao gồm trong một bản cập nhật trong tương lai. Bản sao (với một số thông tin khác) tại đây: stackoverflow.com/questions/40236786/…
Tim Malseed

Câu trả lời:


170

Từ API 25.3.0, nó đã được giới thiệu phương pháp setSelectedItemId(int id)cho phép bạn đánh dấu một mục là đã chọn như thể nó đã được khai thác.

Từ tài liệu:

Đặt ID mục menu đã chọn. Thao tác này tương tự như thao tác chạm vào một mục.

Ví dụ về mã:

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

QUAN TRỌNG

Bạn PHẢI đã thêm tất cả các mục vào menu (trong trường hợp bạn thực hiện việc này theo chương trình) và đặt Trình xử lý trước khi gọi setSelectedItemId (Tôi tin rằng bạn muốn mã trong trình xử lý của mình chạy khi bạn gọi phương thức này). Nếu bạn gọi setSelectedItemId trước khi thêm các mục menu và thiết lập trình lắng nghe sẽ không có gì xảy ra.


3
Điều này KHÔNG HOẠT ĐỘNG, nó chỉ cập nhật bản thân tab, nó không kích hoạt sự kiện
setOnNavigationItemSelectedListener

1
Nếu bạn chưa xác định hành vi thì onTabSelectedrõ ràng nó sẽ không làm được gì cả. Đọc tài liệu -> Đặt ID mục menu đã chọn. Thao tác này hoạt động giống như chạm vào một mục. Nó từ các nhà phát triển Android
Ricardo

1
Tôi thực sự khuyên bạn nên gỡ lỗi và xem lại những gì bạn đang làm sai. Tôi đã triển khai ba Ứng dụng BottomNavigationView và chưa bao giờ gặp sự cố với phương pháp này.
Ricardo

@Ricardo Khi tôi thêm video này vào mảnh của tôi, ứng dụng đã treo trong khi nhập đến đoạn đó
Subin Babu

1
Trong trường hợp của tôi không hoạt động, vì tôi đang tạo navigationMenu theo chương trình. Trong quá trình xây dựng, nhấp chuột không hoạt động. Sau khi tất cả các mục được thêm vào menu, việc gọi setSelectedItemId () đã hoạt động.
Pedro Romão

53

Để lập trình nhấp vào mục BottomNavigationBar bạn cần sử dụng:

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

Điều này sắp xếp tất cả các mục với nhãn của chúng một cách chính xác.


4
Đây là một vụ hack liên quan đến vấn đề. Bạn có các phương thức từ chính thư viện sẽ cho phép bạn thực hiện những gì bạn cần. Nếu bạn không thể thì đó là vì bạn đang làm sai
Ricardo

47

Đối với những người vẫn sử dụng SupportLibrary <25.3.0

Tôi không chắc liệu đây có phải là câu trả lời đầy đủ cho câu hỏi này hay không, nhưng vấn đề của tôi rất giống nhau - tôi phải xử lý thao tác backnhấn nút và đưa người dùng đến tab trước đó nơi anh ta đang ở. Vì vậy, có thể giải pháp của tôi sẽ hữu ích cho ai đó:

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

Xin lưu ý rằng nếu người dùng nhấn tab điều hướng khác BottomNavigationViewsẽ không xóa mục hiện được chọn, vì vậy bạn cần gọi phương thức này onNavigationItemSelectedsau khi xử lý hành động điều hướng:

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

Về việc lưu trạng thái phiên bản, tôi nghĩ bạn có thể chơi với cùng một action idchế độ xem điều hướng và tìm giải pháp phù hợp.


Không Menu menu = bottomNavigationView.getMenu();trả về một bản sao của menu, vì vậy bottomNavigationViewđối tượng không bị ảnh hưởng?
最 白 目

1
@dan Theo nguồn, nó trả về thuộc tính lớp mMenu, không phải bản sao android.googlesource.com/platform/frameworks/support/+/master/…
Viacheslav

6
Bạn không cần phải bỏ chọn các mục khác, ít nhất là vào ngày 26.1.0 / 27.1.0
Jemshit Iskenderov

không làm bỏ chọn, nó sẽ làm nổi bật chúng
djdance

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

action_item1ID mục menu ở đâu .


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

Kể từ phiên bản 25.3.0 hiện có thể gọi setSelectedItemId()\ o /


5

Thêm android:enabled="true"vào các mục BottomNavigationMenu.

Và sau đó thiết lập bottomNavigationView.setOnNavigationItemSelectedListener(mListener)và đặt nó như đã chọn bằng cách thực hiệnbottomNavigationView.selectedItemId = R.id.your_menu_id


3

Điều này có thể sẽ được bổ sung trong các bản cập nhật sắp tới. Nhưng trong khi chờ đợi, để thực hiện điều này, bạn có thể sử dụng phản chiếu.

Tạo một dạng xem tùy chỉnh mở rộng từ BottomNavigationView và truy cập một số trường của nó.

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

}

Và sau đó sử dụng nó trong tệp bố cục xml của bạn.

<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
Suy ngẫm là một ý tưởng tồi!
Filipe Brito

PerformClick tốt hơn là phản chiếu, imho, trong trường hợp này.
Lassi Kinnunen

3

Chỉ cần thêm một cách khác để thực hiện lựa chọn theo chương trình - đây có thể là ý định ngay từ đầu hoặc có thể điều này đã được thêm vào sau này.

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

performIdentifierActioncó một Menuid mục và một cờ.

Xem tài liệu để biết thêm thông tin.


Điều này dường như thực hiện hành động thuộc về mục menu, nhưng không làm cho mục menu xuất hiện đã chọn. Tôi đã nghĩ cái sau là những gì OP muốn, nhưng tôi không tích cực.
LarsH

3

Có vẻ như đã được sửa trong SupportLibrary 25.1.0 :) Chỉnh sửa: Có vẻ như đã được sửa, trạng thái của lựa chọn được lưu khi xoay màn hình.


1
Tôi vừa cập nhật lên 25.1.1. Vấn đề vẫn còn đó.
Xi Wei

3

Trên API 25, bạn có thể sử dụng setSelectedItemId (menu_item_id) nhưng dưới API 25, bạn phải làm khác, người dùng Menu để xử lý và sau đó đặtChecked thành Đã kiểm tra mục cụ thể


3

Sử dụng điều này để đặt mục menu điều hướng dưới cùng đã chọn theo id menu

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

2

Tôi không muốn sửa đổi mã của bạn. Nếu vậy, tôi khuyên bạn nên dùng thử BottomNavigationViewEx

Bạn chỉ cần thay thế gọi một phương thức setCurrentItem(index);getCurrentItem()

Bấm vào đây để xem hình ảnh


2

sử dụng

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

1

Tôi đã báo lỗi cho Google về thực tế là không có cách nào đáng tin cậy để chọn trang trên BottomNavigationView: https://code.google.com/p/android/issues/detail?id=233697

NavigationView dường như đã gặp sự cố tương tự, họ đã khắc phục sự cố này bằng cách thêm phương thức setCheckedItem () mới.


1

Bạn có thể thử phương pháp 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);
    }
}

'Điểm trừ' duy nhất của giải pháp đang sử dụng MenuItemImpl, là 'nội bộ' đối với thư viện (mặc dù công khai).


0

NẾU BẠN CẦN THỰC HIỆN CÁC BIỆN PHÁP ĐỊNH VỊ NĂNG ĐỘNG, HÃY LÀM VIỆC NÀY

Có rất nhiều câu trả lời (hầu hết được lặp lại hoặc đã lỗi thời) ở đây nhưng không có câu trả lời nào trong số chúng giải quyết một nhu cầu rất phổ biến: chuyển động các đối số khác nhau đến Fragment được tải vào tab .

Bạn không thể chuyển động các đối số khác nhau vào Fragment đã tải bằng cách sử dụng setSelectedItemId(R.id.second_tab), điều này kết thúc bằng cách gọi static OnNavigationItemSelectedListener. Để khắc phục hạn chế này, tôi đã kết thúc việc này trong của tôi MainActivitycó chứa các 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()
}

Các ArticleFragment.newInstance()phương pháp được thực hiện như bình thường:

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

Tôi hi vọng cái này giúp được

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

Việc xác định phân đoạn mặc định được tải cùng lúc với mục menu điều hướng dưới cùng tương ứng. Bạn có thể bao gồm điều tương tự trong các lệnh gọi lại OnResume của mình


0

Phương pháp này làm việc cho tôi.

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

Thí dụ

 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

Phản ánh là một ý tưởng tồi.

Đi đến ý chính này . Có một phương thức thực hiện lựa chọn nhưng cũng gọi lại:

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

    }

Tôi sử dụng callOnClick()thay vì performClick(), theo cách này, tôi không cần phải tắt âm thanh, cách này không hoạt động với performClick().
arekolek
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.