0Pricing
Android Academy · Lesson

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 — lesson 5 of 5. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, one of 5 lessons in the course, and your progress syncs across the web and the CoddyKit app.

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 = false

Tab 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.

Frequently asked questions

Is the “Bottom Navigation & Tabs” lesson free?

Yes — the full text of “Bottom Navigation & Tabs” is free to read here on the web, and the Android Academy course includes 5 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Android Academy course, upgrade to CoddyKit PRO.

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; this is — lesson 5 of 5, so you can start here or from the beginning and move at your own pace.

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

  1. Material Design Basics
  2. Themes & Styles
  3. Custom Views
  4. Animations & Transitions
  5. Bottom Navigation & Tabs
← Back to Android Academy