Navigation组件 #

一、Navigation概述 #

Navigation组件是Jetpack提供的导航框架,用于管理应用内的导航,特别是Fragment之间的切换。

1.1 Navigation组件组成 #

  • Navigation Graph:导航图,定义导航路径
  • NavHost:导航容器,显示导航目标
  • NavController:导航控制器,管理导航操作

1.2 添加依赖 #

kotlin
dependencies {
    implementation("androidx.navigation:navigation-fragment-ktx:2.7.6")
    implementation("androidx.navigation:navigation-ui-ktx:2.7.6")
    
    // Safe Args插件
    id("androidx.navigation.safeargs.kotlin")
}

二、导航图 #

2.1 创建导航图 #

xml
<!-- res/navigation/nav_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/homeFragment">
    
    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.HomeFragment"
        android:label="Home"
        tools:layout="@layout/fragment_home">
        
        <action
            android:id="@+id/action_home_to_detail"
            app:destination="@id/detailFragment" />
        
    </fragment>
    
    <fragment
        android:id="@+id/detailFragment"
        android:name="com.example.DetailFragment"
        android:label="Detail"
        tools:layout="@layout/fragment_detail">
        
        <argument
            android:name="itemId"
            app:argType="string" />
        
    </fragment>
    
</navigation>

2.2 NavHostFragment #

xml
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/nav_host_fragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:navGraph="@navigation/nav_graph"
    app:defaultNavHost="true" />

三、导航操作 #

3.1 基本导航 #

kotlin
// 方式1:使用Action ID
findNavController().navigate(R.id.action_home_to_detail)

// 方式2:使用Destination ID
findNavController().navigate(R.id.detailFragment)

// 返回
findNavController().navigateUp()
findNavController().popBackStack()

3.2 传递参数 #

xml
<fragment
    android:id="@+id/detailFragment"
    android:name="com.example.DetailFragment">
    
    <argument
        android:name="itemId"
        app:argType="string" />
    
    <argument
        android:name="count"
        app:argType="integer"
        android:defaultValue="0" />
    
</fragment>
kotlin
// 使用Bundle
val bundle = Bundle().apply {
    putString("itemId", "123")
}
findNavController().navigate(R.id.action_home_to_detail, bundle)

// 在Fragment中获取参数
val itemId = arguments?.getString("itemId")

3.3 Safe Args #

kotlin
// 自动生成的Directions类
val action = HomeFragmentDirections.actionHomeToDetail(itemId = "123")
findNavController().navigate(action)

// 在目标Fragment中获取参数
val args: DetailFragmentArgs by navArgs()
val itemId = args.itemId

3.4 传递对象 #

kotlin
@Parcelize
data class User(val id: String, val name: String) : Parcelable
xml
<argument
    android:name="user"
    app:argType="com.example.User" />
kotlin
val user = User("1", "张三")
val action = HomeFragmentDirections.actionHomeToDetail(user)
findNavController().navigate(action)

四、返回栈管理 #

4.1 popUpTo #

xml
<action
    android:id="@+id/action_to_home"
    app:destination="@id/homeFragment"
    app:popUpTo="@id/homeFragment"
    app:popUpToInclusive="true" />

4.2 清除返回栈 #

kotlin
// 清除返回栈并导航到首页
findNavController().navigate(
    R.id.action_to_home,
    null,
    NavOptions.Builder()
        .setPopUpTo(R.id.nav_graph, true)
        .build()
)

4.3 监听返回事件 #

kotlin
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
    if (hasUnsavedChanges()) {
        showConfirmDialog()
    } else {
        findNavController().navigateUp()
    }
}

五、底部导航 #

5.1 布局配置 #

xml
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:navGraph="@navigation/nav_graph" />
    
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:menu="@menu/bottom_nav_menu" />
        
</LinearLayout>

5.2 导航图配置 #

xml
<navigation>
    <fragment android:id="@+id/homeFragment" ... />
    <fragment android:id="@+id/searchFragment" ... />
    <fragment android:id="@+id/profileFragment" ... />
</navigation>

5.3 菜单配置 #

xml
<!-- res/menu/bottom_nav_menu.xml -->
<menu>
    <item
        android:id="@id/homeFragment"
        android:icon="@drawable/ic_home"
        android:title="首页" />
    <item
        android:id="@id/searchFragment"
        android:icon="@drawable/ic_search"
        android:title="搜索" />
    <item
        android:id="@id/profileFragment"
        android:icon="@drawable/ic_profile"
        android:title="我的" />
</menu>

5.4 绑定Navigation #

kotlin
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController

binding.bottomNav.setupWithNavController(navController)

六、Toolbar与Navigation #

6.1 配置Toolbar #

kotlin
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController

val appBarConfiguration = AppBarConfiguration(navController.graph)
binding.toolbar.setupWithNavController(navController, appBarConfiguration)

6.2 自定义返回按钮 #

kotlin
val appBarConfiguration = AppBarConfiguration(navController.graph)
binding.toolbar.setupWithNavController(navController, appBarConfiguration)

binding.toolbar.setNavigationOnClickListener {
    if (!navController.navigateUp()) {
        onBackPressed()
    }
}

七、深层链接 #

7.1 创建深层链接 #

xml
<fragment
    android:id="@+id/detailFragment"
    android:name="com.example.DetailFragment">
    
    <deepLink
        android:id="@+id/deepLink"
        app:uri="myapp://detail/{itemId}" />
    
    <argument
        android:name="itemId"
        app:argType="string" />
        
</fragment>

7.2 处理深层链接 #

xml
<activity>
    <nav-graph android:value="@navigation/nav_graph" />
</activity>
kotlin
// 在Activity中处理
val deepLink = intent.data
deepLink?.let {
    navController.handleDeepLink(intent)
}

7.3 创建PendingIntent #

kotlin
val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.detailFragment)
    .setArguments(Bundle().apply {
        putString("itemId", "123")
    })
    .createPendingIntent()

八、动画 #

8.1 设置转场动画 #

xml
<action
    android:id="@+id/action_home_to_detail"
    app:destination="@id/detailFragment"
    app:enterAnim="@anim/slide_in_right"
    app:exitAnim="@anim/slide_out_left"
    app:popEnterAnim="@anim/slide_in_left"
    app:popExitAnim="@anim/slide_out_right" />

8.2 共享元素动画 #

kotlin
val extras = FragmentNavigatorExtras(
    binding.imageView to "shared_image"
)

findNavController().navigate(
    R.id.action_home_to_detail,
    null,
    null,
    extras
)
xml
<fragment
    android:id="@+id/detailFragment"
    android:name="com.example.DetailFragment">
    
    <argument
        android:name="itemId"
        app:argType="string" />
    
</fragment>

九、最佳实践 #

9.1 使用ViewModel共享数据 #

kotlin
class SharedViewModel : ViewModel() {
    private val _selectedItem = MutableLiveData<Item>()
    val selectedItem: LiveData<Item> = _selectedItem
    
    fun selectItem(item: Item) {
        _selectedItem.value = item
    }
}

// 在多个Fragment中共享
class ListFragment : Fragment() {
    private val viewModel: SharedViewModel by activityViewModels()
}

class DetailFragment : Fragment() {
    private val viewModel: SharedViewModel by activityViewModels()
}

9.2 使用单一Activity架构 #

kotlin
// 所有导航都在Fragment之间进行
// Activity只作为容器

9.3 处理全局异常 #

kotlin
navController.addOnDestinationChangedListener { _, destination, _ ->
    Log.d("Navigation", "Navigated to ${destination.label}")
}

十、总结 #

本章详细介绍了Navigation组件:

  1. Navigation组件的基本概念
  2. 导航图的创建和配置
  3. 导航操作和参数传递
  4. 返回栈管理
  5. 底部导航集成
  6. Toolbar集成
  7. 深层链接
  8. 动画配置
  9. 最佳实践

Navigation组件简化了Android应用的导航管理,是现代Android开发的重要工具。

最后更新:2026-03-26