📋 Screens, Lists & Navigation · Lesson 26
Bottom Navigation View
When to use bottom navigation
Use a bottom navigation bar for 3–5 top-level screens the user switches between often. Student Diary uses Notes · Subjects · Progress.
Step 1: The menu
The item ids must match destination ids in nav_graph.xml.
XML – res/menu/bottom_nav_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- item ids = destination ids in nav_graph.xml, so setupWithNavController() can link them -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/notesFragment" android:icon="@drawable/ic_note" android:title="@string/menu_notes" />
<item android:id="@+id/subjectsFragment" android:icon="@drawable/ic_subject" android:title="@string/menu_subjects" />
<item android:id="@+id/statsFragment" android:icon="@drawable/ic_stats" android:title="@string/menu_stats" />
</menu>Step 2: Layout
XML
<!-- activity_main.xml (Student Diary, part) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_nav_menu" />
</LinearLayout>Step 3: Link to the NavController
Kotlin
// MainActivity.onCreate (Student Diary)
val navHost = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
navController = navHost.navController
binding.bottomNav.setupWithNavController(navController) // tap item → navigate to same id
// top-level destinations: no ← arrow on these
appBarConfiguration = AppBarConfiguration(
setOf(R.id.notesFragment, R.id.subjectsFragment, R.id.statsFragment /* … */),
binding.drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)Hide it on detail screens
Kotlin
val bottomScreens = setOf(R.id.notesFragment, R.id.subjectsFragment, R.id.statsFragment)
navController.addOnDestinationChangedListener { _, destination, _ ->
binding.bottomNav.isVisible = destination.id in bottomScreens
if (destination.id == R.id.notesFragment) binding.fab.show() else binding.fab.hide()
}Badges
Kotlin
// show "3" on the Notes tab (e.g. pending notes)
viewModel.countAll.observe(this) { total ->
val badge = binding.bottomNav.getOrCreateBadge(R.id.notesFragment)
badge.isVisible = total > 0
badge.number = total
}
// remove it
binding.bottomNav.removeBadge(R.id.notesFragment)Reselect and manual handling
Kotlin
// Tapping the current tab again → scroll the list to the top
binding.bottomNav.setOnItemReselectedListener { item ->
if (item.itemId == R.id.notesFragment) scrollNotesToTop()
}
// Without the Navigation Component (manual fragments)
binding.bottomNav.setOnItemSelectedListener { item ->
val fragment = when (item.itemId) {
R.id.notesFragment -> NotesFragment()
R.id.subjectsFragment -> SubjectsFragment()
else -> StatsFragment()
}
supportFragmentManager.commit { replace(R.id.container, fragment) }
true
}Common mistakes
- Menu ids different from graph ids → nothing happens on tap.
- More than 5 items → labels get hidden and it looks crowded.
- Calling
setOnItemSelectedListeneraftersetupWithNavController→ you replace the navigation listener; use the destination listener instead.
Summary
- Menu with 3–5 items whose ids equal destination ids.
bottomNav.setupWithNavController(navController)+ AppBarConfiguration for top-level screens.- Hide with a destination-changed listener; add badges with
getOrCreateBadge.
✅ Practice
Create a 4-tab app (Home, Search, Saved, Profile) with the Navigation Component. Show a badge with the number of saved items and hide the bar on a details screen.
Frequently Asked Questions
How many items can bottom navigation have?
Three to five. For more destinations use a navigation drawer or tabs.
Does each tab keep its own back stack?
Yes. Since Navigation 2.4, setupWithNavController saves and restores the back stack of each bottom navigation item automatically.
BottomNavigationView or NavigationBarView?
BottomNavigationView extends NavigationBarView. Use BottomNavigationView in XML; extension functions like setupWithNavController accept both.
