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组件:
- Navigation组件的基本概念
- 导航图的创建和配置
- 导航操作和参数传递
- 返回栈管理
- 底部导航集成
- Toolbar集成
- 深层链接
- 动画配置
- 最佳实践
Navigation组件简化了Android应用的导航管理,是现代Android开发的重要工具。
最后更新:2026-03-26