Jetpack Navigation 增加了 Compose 版本依赖,用于实现 Compose 在单个 Compose 树中的导航。还支持 Lifecycle 、 ViewModel 、 Hilt 这些 JetPack 库。
Compse 天生适合单 Activity 开发,对于 Compose 而言,页面切换完全可以通过一次重组来实现,而不应该跳转到新的 Activity 再次生成一个新的 compose 树。
添加依赖 implementation "androidx.navigation:navigation-compose:$nav_version" 最新版本 查看官方 Navigation 页面
Navigation-Compose 使用
配置及导航
- rememberNavController() 创建 NavController
- NavHost() ,传入参数 NavController , NavGraphBuilder (在 NavHost 方法内部生成 NavGraph)。
- 在 NavGraphBuilder 中配置 NavGraph 中的 Destination。
ComposeNavigationDemoTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
val navController = rememberNavController()// 创建 NavController
//创建 NavController , 使用 NavGraphBuilder 设置 NavGraph , 指定第一个启动 Destination 的 route
NavHost(navController = navController, startDestination = "FirstScreen"){
//使用 composable DSL 声明 Destination ,指定 Destination 的 route 和对应的 Compose UI
composable("FirstScreen"){
//将 NavController 传递给 FirstScreen,在 FirstScreen 中控制导航
FirstScreen(navController)
}
composable("SecondScreen"){ SecondScreen(navController) }
}
}
}
- NavController.navigate() 跳转到指定路由
@Composable
fun FirstScreen(navController: NavController){
Scaffold {
Column(modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "FirstScreen")
//navController.navigate() 跳转到指定路由
//指定的路由必须在 NavGraph 中可以找到,不然会抛 IllegalArgumentException 异常
Button(onClick = { navController.navigate("SecondScreen") }) {
Text(text = "Go Second Screen")
}
}
}
}
- navController.navigateUp() 返回上一级路由
@Composable
fun SecondScreen(navController: NavController){
Scaffold(
topBar = { TopAppBar(
title = { Text(text = "Second")},
navigationIcon = { IconButton(onClick = { navController.navigateUp() }) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "")
}}
) }
) {
//......
}
}
导航传参
参数分为必填参数和可选参数,传参需要在 composable DSL 的 route 参数中使用占位符的形式先声明,arguments 参数中指定参数类型
- 必填参数 :
/{参数名} - 可选参数:
?参数名={参数名}, 参数类型必须有默认值 或者nullability = true
参数获取 backStackEntry.arguments?.getString("参数名")
composable(
route = "third/{arg1}?arg2={arg2}",
arguments = listOf(
navArgument("arg1"){type = NavType.StringType},
navArgument(name = "arg2"){ defaultValue = 0 },
)
){ backStackEntry ->
// 参数获取
val arg1 = backStackEntry.arguments?.getString("arg1")!!
val arg2 = backStackEntry.arguments?.getInt("arg2")!!
}
deepLinks
composable DSL 的 deepLinks 参数配置
deepLinks = listOf(
navDeepLink { uriPattern = "test://nav.test.thirdscreen/{arg1}?arg2={arg2}"}
)
配置 Manifest
<!-- 配置 DeepLink -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="test" android:host="nav.test.thirdscreen" />
</intent-filter>
deepLinks 配置看着是不是跟 Destination 配置很像? 因为navigate() 的时候就是对路由进行了包装,这样 route 和 deeplink 就可以使用同一套匹配模式了