| 分类 android  | 标签 Navigation  导航  Fragment  Android  Jetpack 

title

引言

Navigation Component 是 Android Jetpack 的一部分,用于简化应用内导航的实现。它提供了统一的导航 API,支持 Fragment、Activity 以及自定义导航目标,同时自动处理返回栈、过渡动画、深层链接和类型安全的参数传递(Safe Args)。传统方式中,Fragment 的添加、替换、返回栈管理需要大量样板代码,且容易出错。Navigation Component 通过声明式导航图和集中化的 NavController,大幅简化了这些逻辑。本文将深入探讨 Navigation Component 的核心用法、Safe Args、返回栈管理以及最佳实践。

为什么使用 Navigation Component

传统 Fragment 管理依赖 FragmentManagerFragmentTransaction,手动处理 add、replace、addToBackStack 等,代码冗长且易遗漏返回栈逻辑。Navigation Component 将导航结构声明在 XML 导航图中,通过 NavController 执行导航,自动处理返回栈和过渡动画。Safe Args 插件可生成类型安全的导航参数类,避免手写 Bundle 时的键名错误和类型不匹配。此外,Navigation 与 Toolbar、BottomNavigationView 等 UI 组件集成,可自动同步标题和选中状态。

添加依赖

dependencies {
    implementation("androidx.navigation:navigation-fragment-ktx:2.7.6")
    implementation("androidx.navigation:navigation-ui-ktx:2.7.6")
}

若使用 Safe Args,需在项目级 build.gradle 添加 navigation-safe-args-gradle-plugin,并在应用级应用该插件。

创建导航图

导航图是 XML 文件,定义所有导航目标和它们之间的 action。startDestination 指定默认显示的目标。每个 fragment 可定义多个 action,指向不同的 destination。argument 声明目标所需的参数及类型,Safe Args 会根据此生成 *Args*Directions 类。enterAnimexitAnim 等可配置过渡动画。

<!-- res/navigation/nav_graph.xml -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.HomeFragment"
        android:label="Home">
        <action
            android:id="@+id/action_home_to_detail"
            app:destination="@id/detailFragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left" />
    </fragment>

    <fragment
        android:id="@+id/detailFragment"
        android:name="com.example.DetailFragment"
        android:label="Detail">
        <argument
            android:name="itemId"
            app:argType="string" />
    </fragment>
</navigation>

在 Activity 中配置

NavHostFragment 是导航目标的容器,通过 navGraph 指定导航图。defaultNavHost="true" 表示该 NavHost 会拦截系统返回键,用于弹出返回栈而非退出 Activity。Activity 的布局中只需一个 FragmentContainerView,无需为每个 Fragment 单独声明。

<androidx.constraintlayout.widget.ConstraintLayout>
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/nav_graph"
        app:defaultNavHost="true" />
</androidx.constraintlayout.widget.ConstraintLayout>

执行导航

使用 Safe Args 时,通过生成的 *Directions 类创建 action,参数类型安全。也可使用 navigate(resId, bundle) 直接传递 Bundle,但需确保键名和类型与目标声明的 argument 一致。findNavController() 可在 Fragment 或 View 中获取 NavController,需确保调用时 Fragment 已添加到 NavHost。

// 使用 Safe Args 传递参数
val action = HomeFragmentDirections.actionHomeToDetail(itemId = "123")
findNavController().navigate(action)

// 使用 Bundle
findNavController().navigate(
    R.id.detailFragment,
    bundleOf("itemId" to "123")
)

接收参数

使用 Safe Args 时,通过 by navArgs() 委托获取参数,类型安全且无需手动解析 Bundle。navArgs() 会从 arguments 中读取并构造 DetailFragmentArgs 实例。

class DetailFragment : Fragment() {
    private val args: DetailFragmentArgs by navArgs()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val itemId = args.itemId
        loadDetail(itemId)
    }
}

返回栈与 Pop 行为

popBackStack() 弹出栈顶;popBackStack(R.id.homeFragment, false) 弹出直到指定目标(inclusive 参数控制是否包含该目标)。NavOptions 可配置 popUpTo、动画等,实现”跳转到详情并清空中间页”等复杂导航逻辑。例如登录成功后 popUpTo 登录页并 inclusive,可清除登录页及之上的所有页面。

// 弹出到指定目标
findNavController().popBackStack(R.id.homeFragment, false)

// 使用 NavOptions 配置
val navOptions = NavOptions.Builder()
    .setPopUpTo(R.id.homeFragment, true)
    .setEnterAnim(R.anim.slide_in_right)
    .build()
findNavController().navigate(R.id.detailFragment, null, navOptions)

总结

Navigation Component 提供了声明式的导航方式,简化了 Fragment 管理和页面跳转逻辑。掌握导航图、Safe Args、返回栈和 NavOptions,可以构建清晰、可维护的导航结构,并支持深层链接和过渡动画等高级特性。


上一篇     下一篇