Compose () - 使用Navigation

点击跳转 普通使用方式

一、概念

public fun NavHost(
    navController: NavHostController,        //控制器
    startDestination: String,        //默认显示的界面(起始页)
    modifier: Modifier = Modifier,
    route: String? = null,        //用于Navigation嵌套Navigation
    builder: NavGraphBuilder.() -> Unit        //构建导航图
)

public fun NavGraphBuilder.composable(
    route: String,        //路线名称(到哪去)

    arguments: List<NamedNavArgument> = emptyList(),        //获取上个界面跳转携带的参数
    deepLinks: List<NavDeepLink> = emptyList(),        //深层链接
    content: @Composable (NavBackStackEntry) -> Unit
)

val navController = rememberNavController()         //获取控制器。

navController.navigate(“OnePage”)        //页面跳转

navController.navigate(“OnePage”) { launchSingleTop = true }        //singleTop模式

navController.navigate(“TwoPage”) { popUpTo("OnePage") }

navController.navigate(“TwoPage”) { popUpTo("OnePage") { inclusive = true } }

navController.popBackStack()        //返回上一级(相当于点击返回键)。

二、简单跳转

//用单例便于管理路线名称
object RouteConfig {
    const val PAGE_ONE = "1"
    const val PAGE_TWO = "2"
    const val PAGE_THREE = "3"
}
//定义三个页面
@Composable
fun PageOne() {
    Box(modifier = Modifier.background(Color.Blue).fillMaxSize().wrapContentSize(align = Alignment.Center)) {
        Text(text = "Page One", fontSize = 100.sp, color = Color.White)
    }
}
@Composable
fun PageTwo() {
    Box(modifier = Modifier.background(Color.Green).fillMaxSize().wrapContentSize(align = Alignment.Center)) {
        Text(text = "Page Two", fontSize = 100.sp, color = Color.White)
    }
}
@Composable
fun PageThree() {
    Box(modifier = Modifier.background(Color.Red).fillMaxSize().wrapContentSize(align = Alignment.Center)) {
        Text(text = "Page Three", fontSize = 100.sp, color = Color.White)
    }
}
//根节点
@Composable
fun Screen(
    modifier: Modifier = Modifier
) {
    val navController = rememberNavController() //三个按钮属于外部调用跳转,因此在最外层创建控制器
    Column(modifier = modifier.fillMaxSize(), verticalArrangement = Arrangement.Top) {
        SwitchButton(
            modifier = modifier,
            onButtonOneClick = { navController.navigate(RouteConfig.PAGE_ONE) },
            onButtonTwoClick = { navController.navigate(RouteConfig.PAGE_TWO) },
            onButtonThreeClick = { navController.navigate(RouteConfig.PAGE_THREE) }
        )
        SwitchRegion(modifier = modifier, navController = navController)
    }
}
//三个按钮点击切换(状态提升将跳转的处理抛到调用处)
@Composable
fun SwitchButton(
    modifier: Modifier = Modifier,
    onButtonOneClick: () -> Unit,
    onButtonTwoClick: () -> Unit,
    onButtonThreeClick: () -> Unit
) {
    Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround) {
        Button(onClick = onButtonOneClick) { Text(text = "Button One") }
        Button(onClick = onButtonTwoClick) { Text(text = "Button Two") }
        Button(onClick = onButtonThreeClick) { Text(text = "Button Three") }
    }
}
//切换区域
@Composable
fun SwitchRegion(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(), //提供默认实现(如果外部没有调用跳转就不用传了)
    startDestination: String = RouteConfig.PAGE_ONE
) {
    NavHost(modifier = modifier, navController = navController, startDestination = startDestination) {
        composable(route = RouteConfig.PAGE_ONE) { PageOne() }
        composable(route = RouteConfig.PAGE_TWO) { PageTwo() }
        composable(route = RouteConfig.PAGE_THREE) { PageThree() }
    }
}

三、单一可信来源

不管是 NavHost 外部有控制其跳转,还是 NavHost 内部子界面有调用跳转,都应该将跳转抽取成函数形参供调用处处理(外部控制的调用处使用的navController传给NavHost做到状态共享,子界面的调用处是NavHost的composable中),而不是形参传入一个NavHost供自己内部使用。

NavHost(modifier = modifier, navController = navController, startDestination = startDestination) {
    composable("profile") {
        ProfileScreen(onNavigateToFriends = { navController.navigate("friendsList") })
    }
    composable("friendslist") { FriendsListScreen() }
}
//子界面有跳转
@Composable
fun ProfileScreen(onNavigateToFriends: () -> Unit) {
    Button(onClick = onNavigateToFriends) {
        Text(text = "See friends list")
    }
}

四、携带参数跳转

跳转官方可携带数据类型说明

界面跳转应该传递简单的必要的数据(如标识ID等),需要传递复杂的数据,应该将这些数据保存在数据层,跳转到新界面后根据ID到数据层获取。通过路线处理参数的结构意味着组合将完全独立于 Navigation 并且更易于测试。

NavHost(startDestination = "pageProfile/{userId}") {
    composable(
        route = "pageProfile/{userId}", //向路线中添加占位符
        arguments = listOf(    //往集合中添加参数(NamedNavArgument类型)
            navArgument(name = "userId") {
                type = NavType.StringType   //默认情况下参数都会被解析成字符串,需要指定具体类型
                defaultValue = "123456" //默认值(选配)
                nullable = false    //可否为null(选配)
            }
        )
    ){ navBackStackEntry ->
        val id = navBackStackEntry.arguments?.getString("userId")   //提取参数
    }
}
//跳转
navController.navigate("profile/user1234")

五、可选参数

必须使用查询参数语法来添加,必须提供默认值或 nullable = true。

composable(
    "pageProfile?userId={userId}",
    arguments = listOf(
        navArgument("userId") { defaultValue = "user1234" }
    )
) { backStackEntry ->
     backStackEntry.arguments?.getString("userId")
}

 六、深层链接 Deep Link

深层链接可以响应其他界面或外部APP的跳转。

6.1 本应用内跳转

val uri = "https://www.example.com"
composable(
    "pageProfile?id={id}",
    deepLinks = listOf(navDeepLink { uriPattern = "$uri/{id}" })
) { backStackEntry ->
    Profile(navController, backStackEntry.arguments?.getString("id"))
}

6.2 响应外部跳转

<activity …>
  <intent-filter>
    ...
    <data android:scheme="https" android:host="www.example.com" />
  </intent-filter>
</activity>

6.3 PendingIntent

val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
    Intent.ACTION_VIEW,
    "https://www.example.com/$id".toUri(),
    context,
    MyActivity::class.java
)

val deepLinkPendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
    addNextIntentWithParentStack(deepLinkIntent)
    getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}

七、嵌套导航

Navigation中嵌套Navigation。

//一般写法
NavHost(navController, startDestination = "home") {
    navigation(startDestination = "username", route = "login") {
        composable("username") { ... }
        composable("password") { ... }
        composable("registration") { ... }
    }
}
//建议用扩展函数方便使用
fun NavGraphBuilder.loginGraph(navController: NavController) {
    navigation(startDestination = "username", route = "login") {
        composable("username") { ... }
        composable("password") { ... }
        composable("registration") { ... }
    }
}
//NavHost中使用
NavHost(navController, startDestination = "home") {
    loginGraph(navController)
}

猜你喜欢

转载自blog.csdn.net/HugMua/article/details/130178076