Search code examples
androidbottomnavigationviewandroid-viewmodel

Android BottomNavigationView ViewModel setting state programmatically


I am trying to move my bottom sheet navigation state to a viewmodel. This will enable me to set the tab programmatically and also save the tab state on rotation.

In the viewmodel: enum class NavTab { TAB_1, TAB_2, TAB_3 }

val navigationTab: LiveData<NavigationTab> = savedStateHandle.getLiveData("nav_tab")
fun setNavigationTab(tab: NavigationTab) {
    savedStateHandle.set("nav_tab", tab)
}

In the activity:

bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnItemSelectedListener(item -> {
    switch (item.getItemId()) {
        case R.id.tab_1:
            viewModel.setNavigationTab(NavTab.TAB_1);
            break;
        case R.id.tab_2:
            viewModel.setNavigationTab(NavTab.TAB_2);
            break;
        case R.id.tab_3:
            viewModel.setNavigationTab(NavTab.TAB_3);
            break;
    }

    return true;
});

viewModel.getNavigationTab().observe(this, this::onNavigationTab);
private void onNavigationTab(NavTab tab) {
    switch (tab) {
        case TAB_1:
            bottomNavigationView.setSelectedItemId(R.id.tab_1);
            break;
        case TAB_2:
            bottomNavigationView.setSelectedItemId(R.id.tab_2);
            break;
        case TAB_3:
            bottomNavigationView.setSelectedItemId(R.id.tab_3);
            break;
    }
}

However the problem is when setting the tab programmatically by calling setNavigationTab only the fragment is switching the tab is not property selected. I can call

bottomNavigationView.setSelectedItemId(R.id.tab_2);

However if I do this, the view model will see the change and fire the observer, causing an infinite loop.

In the case of programmatically changing the tab I need to switch the fragment and the UI tab. In case of user clicking the tab, I only need to set the fragment as the tab UI is changed appropriately.


Solution

  • You can mark tabs as checked without setting the selected item and therefore not calling the selected item listener as follows:

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