'BottomNavigationView with navigation component - selected fragment not showing
I'm currently migrating to android navigation component and cannot get the fragment transitions to work when a new item is being selected in the BottomNavigationView. I followed the instructions in the official documentation and I did not found any issues why the selected fragment is not being displayed.
In the activity in the onCreate method im setting the nav controller:
NavController navController = Navigation.findNavController(this, R.id.fragment_main_layout_nav_host);
NavigationUI.setupActionBarWithNavController(this, navController);
NavigationUI.setupWithNavController(binding.includedAppbarMain.bottomNavigationViewMainAppbar, navController);
The layout contains the nav host fragment and the BottomNavigationView:
<fragment
android:id="@+id/fragment_main_layout_nav_host"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/activity_main"
app:defaultNavHost="true"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation_view_main_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/activity_main_bottom_navigation" />
Menu for the BottomNavigationView:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_activity_main_home"
android:title="Home"
android:enabled="true"
android:icon="@drawable/ic_home_24dp"/>
<item
android:id="@+id/action_activity_main_notebooks"
android:title="Notebooks"
android:enabled="true"
android:icon="@drawable/ic_file_24dp"/>
<item
android:id="@+id/action_activity_main_search"
android:title="Search"
android:enabled="true"
android:icon="@drawable/ic_search_24dp"/>
</menu>
Navigation:
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
app:startDestination="@id/action_activity_main_home">
<fragment
android:id="@+id/action_activity_main_home"
android:name="com.inknotes.view.fragment.MainHomeFragment"
android:label="@string/main_vertical_navigation_home"
tools:layout="@layout/fragment_main_home" />
<fragment
android:id="@+id/action_activity_main_notebooks"
android:name="com.inknotes.view.fragment.MainNotebookFragment"
android:label="@string/main_vertical_navigation_notebooks"
tools:layout="@layout/fragment_main_notebook" />
<fragment
android:id="@+id/action_activity_main_search"
android:name="com.inknotes.view.fragment.MainSearchFragment"
android:label="@string/main_vertical_navigation_search"
tools:layout="@layout/fragment_main_search" />
</navigation>
The ids of the menu items and fragments are also matching and i'm running out of ideas why the new fragment is not being displayed when i select another item in the BottomNavigationView.
Edit 1:
I did some more testing and found out that popping the fragments from the backstack also does not work, maybe I have some generel issues with my nav controller?
Edit 2:
MainActivity (I removed some stuff because it would be too long):
@MainActivityScope
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2, MainActivityHandler,
SpeedDialView.OnActionSelectedListener, BottomNavigationView.OnNavigationItemSelectedListener {
// Static variables
public static final String EXTRA_PATH = "com.inknotes.EXTRA_PATH";
// Injected objects
@Inject MainHomeFragment mainHomeFragment;
@Inject MainFolderFragment mainFolderFragment;
@Inject MainNotebookFragment mainNotebookFragment;
@Inject MainSearchFragment mainSearchFragment;
@Inject MainFolderAddDialog mainFolderAddDialog;
@Inject MainNotebookAddDialog mainNotebookAddDialog;
@Inject MainNotebookActionModeCallback mainNotebookActionModeCallback;
@Inject MainFolderActionModeCallback mainFolderActionModeCallback;
@Inject FileHelper fileHelper;
@Inject ClipboardHelper clipboardHelper;
@Inject ViewModelProvider.Factory viewModelFactory;
@Inject MainVerticalNavigationAdapter mainVerticalNavigationAdapter;
@Inject XmlParser<OptionItem> xmlParser;
// Objects
public MainActivityComponent daggerMainActivityComponent;
private ActivityMainBinding binding;
private MainViewModel mainViewModel;
private MainFolderViewModel mainFolderViewModel;
private MainNotebookViewModel mainNotebookViewModel;
private GestureDetectorCompat gestureDetectorCompat;
private MenuItem searchMenuItem;
private SelectionTracker<Long> verticalNavigationSelectionTracker;
private NavController navController;
// Variables
private boolean isBackPressed = false;
// =============================================================================================
//region Base methods
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(
this,
R.layout.activity_main,
new BindingComponent(this));
binding.setLifecycleOwner(this);
// Set the main dagger component
daggerMainActivityComponent = ((InkNotesApplication) getApplication())
.component()
.mainActivityComponentFactory()
.create(this);
daggerMainActivityComponent.inject(this);
// Get all viewModels
mainViewModel = new ViewModelProvider(this, viewModelFactory).get(MainViewModel.class);
mainFolderViewModel = new ViewModelProvider(this, viewModelFactory).get(MainFolderViewModel.class);
mainNotebookViewModel = new ViewModelProvider(this, viewModelFactory).get(MainNotebookViewModel.class);
// Set the default file
mainViewModel.setDefaultFile(getExternalFilesDir("notes"));
mainViewModel.setCurrentFile(getExternalFilesDir("notes"));
gestureDetectorCompat = new GestureDetectorCompat(this, new GestureListener());
// Set variables of binding
binding.setHandler(this);
binding.setViewModel(mainViewModel);
// Setup main toolbar
setSupportActionBar(binding.includedAppbarMain.materialToolbarMainAppbar);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu_24dp);
// Setup explorer toolbar
binding.includedAppbarFolder.materialToolbarFolder.setOnMenuItemClickListener(this::onOptionsItemSelected);
// Setup drawer and navigation layout
binding.navigationViewMainFolder.setVisibility(View.GONE);
if (binding.drawerLayoutMain != null) {
binding.drawerLayoutMain.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
binding.drawerLayoutMain.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
if (mainFolderActionModeCallback != null) {
mainFolderActionModeCallback.finish();
}
}
});
}
// Setup navigation
navController = Navigation.findNavController(this, R.id.fragment_main_layout_nav_host);
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
navController.getGraph()
).build();
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
if (binding.includedAppbarMain.bottomNavigationViewMainAppbar != null) {
NavigationUI.setupWithNavController(binding.includedAppbarMain.bottomNavigationViewMainAppbar, navController);
}
// Set the explorer and file card fragment
/*
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout_main_layout_fragment_container, mainHomeFragment).commit();*/
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout_main_folder_container, mainFolderFragment).commit();
// Setup the floating action button
binding.includedAppbarMain.speedDialViewMainAppbar.inflate(R.menu.activity_main_fab);
binding.includedAppbarMain.speedDialViewMainAppbar.setOnActionSelectedListener(this);
// Setup bottom navigation view
if (binding.includedAppbarMain.bottomNavigationViewMainAppbar != null) {
binding.includedAppbarMain.bottomNavigationViewMainAppbar.setOnNavigationItemSelectedListener(this);
}
// Setup the vertical navigation view
if (binding.recyclerViewMainVerticalNavigation != null) {
binding.recyclerViewMainVerticalNavigation.setAdapter(mainVerticalNavigationAdapter);
List<OptionItem> items = xmlParser.parse(getResources().getXml(R.xml.menu_main_vertical_navigation), OptionItem.class);
// Create the selection tracker
// Add observer to the selection tracker
mainVerticalNavigationAdapter.setSelectionTracker(verticalNavigationSelectionTracker);
verticalNavigationSelectionTracker.select((long) R.id.action_activity_main_vertical_navigation_home);
mainVerticalNavigationAdapter.submitList(items);
binding.includedAppbarMain.speedDialViewMainAppbar.setVisibility(View.INVISIBLE);
toggleFolderNavigationView(View.VISIBLE);
}
}
@Override
public void onBackPressed() {
if (binding.drawerLayoutMain != null) {
if (binding.drawerLayoutMain.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayoutMain.closeDrawer(GravityCompat.START);
}
}
super.onBackPressed();
}
@Override
public boolean onSupportNavigateUp() {
if (binding.drawerLayoutMain != null) {
return NavigationUI.navigateUp(navController, binding.drawerLayoutMain);
}
return super.onSupportNavigateUp();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetectorCompat.onTouchEvent(event);
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(@NonNull MotionEvent event) {
super.dispatchTouchEvent(event);
return gestureDetectorCompat.onTouchEvent(event);
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
selectNavigationItem(item.getItemId());
return true;
}
//endregion
// =============================================================================================
//region Custom methods
private void selectNavigationItem(int id) {
switch (id) {
case R.id.action_activity_main_home:
case R.id.action_activity_main_vertical_navigation_home:
//navController.navigate(R.id.action_activity_main_home);
if (binding.drawerLayoutMain != null) {
binding.drawerLayoutMain.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(false);
if (searchMenuItem != null) {
searchMenuItem.collapseActionView();
}
binding.includedAppbarMain.appBarLayoutMainAppbar.setExpanded(true);
binding.includedAppbarMain.speedDialViewMainAppbar.setVisibility(View.INVISIBLE);
toggleFolderNavigationView(View.VISIBLE);
break;
case R.id.action_activity_main_notebooks:
case R.id.action_activity_main_vertical_navigation_notebooks:
//navController.navigate(R.id.action_activity_main_notebooks);
if (binding.drawerLayoutMain != null) {
binding.drawerLayoutMain.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
if (searchMenuItem != null) {
searchMenuItem.collapseActionView();
}
binding.includedAppbarMain.appBarLayoutMainAppbar.setExpanded(true);
binding.includedAppbarMain.speedDialViewMainAppbar.setVisibility(View.VISIBLE);
toggleFolderNavigationView(View.GONE);
break;
case R.id.action_activity_main_search:
case R.id.action_activity_main_vertical_navigation_search:
//navController.navigate(R.id.action_activity_main_search);
if (binding.drawerLayoutMain != null) {
binding.drawerLayoutMain.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(false);
if (searchMenuItem != null) {
searchMenuItem.expandActionView();
}
binding.includedAppbarMain.appBarLayoutMainAppbar.setExpanded(false);
binding.includedAppbarMain.speedDialViewMainAppbar.setVisibility(View.INVISIBLE);
toggleFolderNavigationView(View.VISIBLE);
break;
}
isBackPressed = false;
}
In the selectNavigationItem method you can also see that I tested to navigate manually with navController.navigate(R.id.action_activity_main_notebooks);
, that worked but popping the backstack also didn't work. But setting the BottomNavigationView with NavigationUI.setupWithNavController(binding.includedAppbarMain.bottomNavigationViewMainAppbar, navController);
should make it unnecessary to call navigate.
HomeFragment:
@MainActivityScope
public class MainHomeFragment extends Fragment {
public final static String NAME = "MainHomeFragment";
@Inject
public MainHomeFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main_home, container, false);
}
}
NotebookFragment:
@MainActivityScope
public class MainNotebookFragment extends Fragment {
// Static variables
public final static String NAME = "MainNotebookFragment";
private static final String ARG_COLUMN_COUNT = "column-count";
// Injected objects
@Inject ViewModelProvider.Factory viewModelFactory;
@Inject MainNotebookAdapter mainNotebookAdapter;
@Inject MainNotebookItemTouchHelperCallback mainNotebookItemTouchHelperCallback;
// Objects
private RecyclerView recyclerView;
private MainNotebookViewModel mainNotebookViewModel;
// Variables
private int columnCount = 4;
@Inject
public MainNotebookFragment() {
}
// =============================================================================================
//region Base methods
@Override
public void onCreate(Bundle savedInstanceState) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
columnCount = getResources().getInteger(R.integer.column_count_portrait);
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
columnCount = getResources().getInteger(R.integer.column_count_landscape);
}
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main_notebook, container, false);
((MainActivity) requireActivity()).daggerMainActivityComponent.inject(this);
mainNotebookViewModel = new ViewModelProvider(requireActivity(), viewModelFactory).get(MainNotebookViewModel.class);
if (getArguments() != null) {
columnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
// Set the mainNotebookAdapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
recyclerView = (RecyclerView) view;
if (columnCount <= 1) {
recyclerView.setLayoutManager(new LinearLayoutManager(context));
} else {
recyclerView.setLayoutManager(new GridLayoutManager(context, columnCount));
}
recyclerView.setAdapter(mainNotebookAdapter);
}
// Set the item touch helper
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mainNotebookItemTouchHelperCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mainNotebookViewModel.getItems().observe(
getViewLifecycleOwner(),
fileCardItems -> mainNotebookAdapter.setItems(fileCardItems)
);
mainNotebookViewModel.getSelectedItems().observe(
getViewLifecycleOwner(),
selectedExplorerItems -> mainNotebookAdapter.setSelectedItems(selectedExplorerItems)
);
mainNotebookViewModel.getQueryText().observe(
getViewLifecycleOwner(),
queryText -> mainNotebookAdapter.getFilter().filter(queryText)
);
}
@Override
public void onResume() {
super.onResume();
if (!EventBus.getDefault().isRegistered(mainNotebookAdapter)) {
EventBus.getDefault().register(mainNotebookAdapter);
}
}
@Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(mainNotebookAdapter);
}
//endregion
}
SearchFragment:
@MainActivityScope
public class MainSearchFragment extends Fragment {
public final static String NAME = "MainSearchFragment";
@Inject
public MainSearchFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main_search, container, false);
}
}
Solution 1:[1]
I finally found the solution, the problem was the onNavigationItemSelected
function. So either removing those two parts from the MainActivity resolves the issue:
if (binding.includedAppbarMain.bottomNavigationViewMainAppbar != null) {
binding.includedAppbarMain.bottomNavigationViewMainAppbar.setOnNavigationItemSelectedListener(this);
}
...
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
selectNavigationItem(item.getItemId());
return true;
}
Or what I did, because I stil need the function, return NavigationUI.onNavDestinationSelected(item, navController)
instead of true.
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
selectNavigationItem(item.getItemId());
return NavigationUI.onNavDestinationSelected(item, navController);
}
Solution 2:[2]
Finally got resolved my issue , when i am using a nav graph where many fragment and actions occur for a bottom navigation component where only 5 menu available .
my issue was when i am visit any menu then it show active stag but when i visit twise which is already visit then no active stag show .. Means that no active color showing after navigating fragment.
Fixed with this solution :-
app:popUpTo="@id/homeFragment" app:popUpToInclusive="true"
<fragment
android:id="@+id/addAccountFragment"
android:name="app.ph7.doctor.ui.screens.home.addAccount.AddAccountFragment"
android:label="AddAccountFragment"
tools:layout="@layout/fragment_add_account">
<action
android:id="@+id/action_addAccountFragment_to_accDetailsFragment"
app:destination="@id/accDetailsFragment" />
<action
android:id="@+id/action_addAccountFragment_to_notificationFragment"
app:destination="@id/notificationFragment" />
<action
android:id="@+id/action_addAccountFragment_to_appointmentFragment"
app:destination="@id/appointmentFragment"
app:popUpTo="@id/homeFragment"
app:popUpToInclusive="true" />
</fragment>
Here homefragment is startDestination
<navigation
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/dashboard_navigation"
app:startDestination="@id/homeFragment">
Hope your problem resolved ..
Solution 3:[3]
As official document says -
NavController manages app navigation within a NavHost.
Apps will generally obtain a controller directly from a host, or by using one of the utility methods on the Navigation class rather than create a controller directly.
When you are creating your navController, make sure you are assigning it the id of your navigation host fragment. This is how you are creating your navController.
NavController navController = Navigation.findNavController(this, R.id.fragment_main_layout);
// issue here, use R.id.fragment_main_layout_nav_host
while the id of nav host fragment in your xml is -
<fragment>
android:id="@+id/fragment_main_layout_nav_host"
.....
</fragment>
Make sure you are using same id.
Happy Coding !!
Solution 4:[4]
You are using the wrong id of the host fragment when initializing the NavController
You need to replace
NavController navController = Navigation.findNavController(this, R.id.fragment_main_layout);
with
NavController navController = Navigation.findNavController(this, R.id.fragment_main_layout_nav_host);
Solution 5:[5]
``Did you initialize BottomNavigationView
BottomNavigationView bottomNavigationView =binding.bottomNavigationAppBar
and call bottomNavigationView in
NavigationUI.setupWithNavController(bottomNavigationView,
navController);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Timo S. |
Solution 2 | Surajkaran Meghwanshi |
Solution 3 | |
Solution 4 | Zain |
Solution 5 | ismailfarisi |