5 .1 Navigation-Compose 简单使用

712 阅读2分钟

Jetpack Navigation 增加了 Compose 版本依赖,用于实现 Compose 在单个 Compose 树中的导航。还支持 Lifecycle 、 ViewModel 、 Hilt 这些 JetPack 库。

Compse 天生适合单 Activity 开发,对于 Compose 而言,页面切换完全可以通过一次重组来实现,而不应该跳转到新的 Activity 再次生成一个新的 compose 树。

添加依赖 implementation "androidx.navigation:navigation-compose:$nav_version"  最新版本 查看官方 Navigation 页面

Navigation-Compose  使用

配置及导航

  1. rememberNavController() 创建 NavController
  2. NavHost() ,传入参数 NavController , NavGraphBuilder (在 NavHost 方法内部生成 NavGraph)。 
  3. 在 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) }
        }
    }
}
  1. 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")
            }
        }
    }
}
  1. 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 = "")
            }}
        ) }
    ) {
        //......
    }
}

Untitled.gif

导航传参

参数分为必填参数和可选参数,传参需要在 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>

AE062A9B-DEA1-4C4A-92F3-626A8513C438.png

deepLinks 配置看着是不是跟 Destination 配置很像? 因为navigate() 的时候就是对路由进行了包装,这样 route 和 deeplink 就可以使用同一套匹配模式了

FAFE9923-3A4F-4F2A-96E3-81DA731D9A8C.png