Android Academy · 课时

底部导航与标签页

使用连接到 NavController 的 BottomNavigationView 实现多分区导航,并使用 TabLayout、ViewPager2 和 TabLayoutMediator 实现可滑动标签页。

第 5 / 5 课13 个步骤

底部导航与标签页 是 CoddyKit 上的免费 Android Academy 课时。 这是第 5 节课,共 5 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 5 节课。

导航模式

Android 应用中两种常见的顶层导航模式:

  • 底部导航 — 适用于 3–5 个主要目的地。始终可见。最适合重要性相同的区域(例如首页、搜索和个人资料)。
  • 标签页 — 适用于同一屏幕中的相关内容(例如全部/进行中/已完成)。通常与 ViewPager2 搭配使用,以支持滑动切换。

BottomNavigationView 布局

将 BottomNavigationView 和 FragmentContainerView 添加到您的 Activity 布局中:

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

底部导航菜单项

在 res/menu/bottom_nav_menu.xml 中定义菜单项。每个菜单项的 ID 必须与导航图中的目的地 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>

连接到 NavController

在 onCreate() 中将 BottomNavigationView 连接到 NavController:

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
            }
        }
    }
}

底部导航中的徽章

在底部导航菜单项上显示通知徽章:

// 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 显示水平标签页,通常与 ViewPager2 搭配使用,以展示可滑动切换的内容:

<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

创建一个适配器,为每个标签页位置提供一个片段:

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

使用 TabLayoutMediator 连接 ViewPager2 和 TabLayout:

// 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

带图标的标签页

为 TabLayout 的标签页添加图标:

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()

屏外页面限制

默认情况下,ViewPager2 只会将相邻页面保留在内存中。如果切换标签页时仍希望页面保持活动状态,请增大 offscreenPageLimit:

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

底部导航与标签页:如何选择

选择合适模式的快速指南:

  • 使用底部导航:有 3–5 个用途不同的顶层目的地(首页、搜索、通知、个人资料)
  • 使用标签页:对同类内容进行筛选或分类(全部/进行中/已归档的任务)
  • 组合使用:用底部导航切换顶层区域,在某个区域内使用标签页进行二级筛选

快速检查

哪个类负责连接 TabLayout 和 ViewPager2,并设置标签页标题?

回顾:底部导航与标签页

正确实现多区域导航:

  • BottomNavigationView — 3–5 个重要性相同的目的地,菜单 ID 与导航图目的地 ID 匹配
  • setupWithNavController() — 自动切换标签页并管理返回栈
  • 使用 getOrCreateBadge() 添加徽章
  • TabLayout + ViewPager2 — 以滑动方式查看同一内容的筛选视图
  • TabLayoutMediator — 连接两者并设置标题

下一节:使用 JUnit 进行单元测试,让您的代码更加可靠。

免费开始

用 AI 导师学习 Kotlin — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
36
课程
152

常见问题解答

「底部导航与标签页」课时是免费的吗?

是的 — 「底部导航与标签页」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 5 节课。

「底部导航与标签页」这节课中我会学到什么?

使用连接到 NavController 的 BottomNavigationView 实现多分区导航,并使用 TabLayout、ViewPager2 和 TabLayoutMediator 实现可滑动标签页。 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Android Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 5 节课,共 5 节。

「底部导航与标签页」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Android Academy 课中编写并运行代码吗?

能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Material Design 基础
  2. 主题与样式
  3. 自定义视图
  4. 动画与过渡
  5. 底部导航与标签页
← 返回 Android Academy