Bottom Navigation & Tabs
Implement multi-section navigation with BottomNavigationView connected to NavController, and swipeable tabs with TabLayout, ViewPager2, and TabLayoutMediator.
Bottom Navigation & Tabs is a free Android Academy lesson on CoddyKit. This is lesson 5 of 5. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, and your progress syncs across the web and the CoddyKit app. The Android Academy course includes 5 lessons in total.
Navigation Patterns
Two common patterns for top-level navigation in Android apps:
- Bottom Navigation — for 3–5 primary destinations. Always visible. Best for equal-importance sections (e.g., Home, Search, Profile).
- Tabs — for related content within a screen (e.g., All / Active / Done). Often used with ViewPager2 for swipe support.
BottomNavigationView Layout
Add BottomNavigationView and a FragmentContainerView to your Activity layout:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/navHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true" />
<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>Bottom Nav Menu Items
Define items in res/menu/bottom_nav_menu.xml. Each item ID must match a navigation graph destination ID:
<!-- res/menu/bottom_nav_menu.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/homeFragment"
android:icon="@drawable/ic_home"
android:title="Home" />
<item
android:id="@+id/searchFragment"
android:icon="@drawable/ic_search"
android:title="Search" />
<item
android:id="@+id/profileFragment"
android:icon="@drawable/ic_person"
android:title="Profile" />
</menu>Connecting to NavController
Wire BottomNavigationView to the NavController in onCreate():
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHost = supportFragmentManager
.findFragmentById(R.id.navHostFragment) as NavHostFragment
val navController = navHost.navController
binding.bottomNav.setupWithNavController(navController)
// Hide bottom nav on detail screens:
navController.addOnDestinationChangedListener { _, destination, _ ->
binding.bottomNav.visibility = when (destination.id) {
R.id.detailFragment -> View.GONE
else -> View.VISIBLE
}
}
}
}Badges on Bottom Nav
Show notification badges on bottom nav items:
// Show a numbered badge:
val badge = binding.bottomNav.getOrCreateBadge(R.id.homeFragment)
badge.number = 5
badge.isVisible = true
// Show dot badge (no number):
val dotBadge = binding.bottomNav.getOrCreateBadge(R.id.searchFragment)
dotBadge.isVisible = true
// Remove badge:
binding.bottomNav.removeBadge(R.id.homeFragment)TabLayout
TabLayout shows horizontal tabs, typically used with ViewPager2 for swipeable content:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>ViewPager2 + FragmentStateAdapter
Create an adapter that provides a fragment for each tab position:
class TasksPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
override fun getItemCount() = 3
override fun createFragment(position: Int): Fragment = when (position) {
0 -> AllTasksFragment()
1 -> ActiveTasksFragment()
2 -> CompletedTasksFragment()
else -> throw IllegalStateException("Unknown tab $position")
}
}TabLayoutMediator
Connect ViewPager2 and TabLayout with TabLayoutMediator:
// In Fragment.onViewCreated():
val adapter = TasksPagerAdapter(this)
binding.viewPager.adapter = adapter
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.text = when (position) {
0 -> "All"
1 -> "Active"
2 -> "Done"
else -> ""
}
}.attach()
// Disable swipe if needed:
binding.viewPager.isUserInputEnabled = falseTab with Icons
Add icons to TabLayout tabs:
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
when (position) {
0 -> {
tab.text = "Home"
tab.setIcon(R.drawable.ic_home)
}
1 -> {
tab.text = "Search"
tab.setIcon(R.drawable.ic_search)
}
2 -> {
tab.text = "Profile"
tab.setIcon(R.drawable.ic_person)
}
}
}.attach()Offscreen Page Limit
By default, ViewPager2 only keeps the adjacent page in memory. Increase offscreenPageLimit if your tabs should stay alive when switching:
// Keep 2 pages on each side alive:
binding.viewPager.offscreenPageLimit = 2
// Note: FragmentStateAdapter saves and restores state for off-screen
// fragments even when offscreenPageLimit is 1 (default).
// Only increase this when you need views (not just state) to survive.Bottom Nav vs Tabs: Choosing
Quick guide for picking the right pattern:
- Use Bottom Navigation when: 3–5 top-level destinations with different purposes (Home, Search, Notifications, Profile)
- Use Tabs when: filtering or categorizing the same type of content (All / Active / Archived tasks)
- Combine both: Bottom Nav for top-level sections, Tabs inside a section for sub-filtering
Quick Check
Which class connects a TabLayout to a ViewPager2 and sets the tab labels?
Recap: Bottom Navigation & Tabs
Multi-section navigation done right:
- BottomNavigationView — 3–5 equal-importance destinations, menu IDs match nav graph destination IDs
setupWithNavController()— auto tab switching + back stack- Badges with
getOrCreateBadge() - TabLayout + ViewPager2 — swipeable, filtered views of the same content
TabLayoutMediator— connects the two and sets labels
Next: Unit Testing with JUnit to keep your code reliable.
Learn Kotlin with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 36
- Lessons
- 152
Frequently Asked Questions
Is the “Bottom Navigation & Tabs” lesson free?
Yes — any 3 lessons of the Android Academy learning path, including “Bottom Navigation & Tabs”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Android Academy course includes 5 lessons in total.
What will I learn in “Bottom Navigation & Tabs”?
Implement multi-section navigation with BottomNavigationView connected to NavController, and swipeable tabs with TabLayout, ViewPager2, and TabLayoutMediator. You practise Android Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Android Academy?
No prior experience is required. Android Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 5 of 5.
How long does the “Bottom Navigation & Tabs” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Android Academy lesson?
Yes. Every Android Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Material Design Basics
- Themes & Styles
- Custom Views
- Animations & Transitions
- Bottom Navigation & Tabs