Compose 使用Navigation

Compose 使用Navigation

概述

Navigation也是Jetpack中的导航库,它可以处理多个Fragment之间的跳转、传值等操作。Compose本身不提供任何页面导航的能力,因此Navigation专门为Compose做了适配,让我们在Compose中也可以完美地进行页面之间的跳转。

添加依赖库

implementation "androidx.navigation:navigation-compose:2.5.1"

使用

基本概念

NavDestination:页面导航中跳转到各个节点。

NavigationGraph:页面导航中各节点的跳转关系。

NavHost:显示节点的容器。

NavController:管理跳转行为。

简单使用

  • 使用 rememberNavController() 创建 NavController 实例。
  • 使用 NavHost() 提供导航容器。
  • 使用 composable() 声明路由。
  • 使用 navigate() 页面跳转。
  • NavHostController#navigate():跳转指定页面。
  • NavHostController#navigateUp():返回上一个页面。
public fun NavHost(
    navController: NavHostController, // 控制器
    startDestination: String, // 默认路径
    modifier: Modifier = Modifier, // 修饰符
    route: String? = null, // 路径
    builder: NavGraphBuilder.() -> Unit
)
@Composable
fun BasePage(content: String, navController: NavHostController, handleClick: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(content, fontSize = 35.sp)
        Button(onClick = { handleClick() }) {
            Text("跳转")
        }
        Button(onClick = { navController.navigateUp() }) {
            Text("返回上一个")
        }
    }
}

@Composable
fun OnePage(navController: NavHostController) {
    BasePage("OnePage", navController) {
        navController.navigate("two_page")
    }
}

@Composable
fun TwoPage(navController: NavHostController) {
    BasePage("TwoPage", navController) {
        navController.navigate("three_page")
    }
}

@Composable
fun ThreePage(navController: NavHostController) {
    BasePage("ThreePage", navController) {
        navController.navigate("one_page")
    }
}

@Composable
fun MyNavigation() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "one_page"
    ) {
        composable("one_page") {
            OnePage(navController)
        }
        composable("two_page") {
            TwoPage(navController)
        }
        composable("three_page") {
            ThreePage(navController)
        }
    }
}

跳转方式

navController.navigate("home") {
    popUpTo("welcome")
}

说明:清空当前节点到welcome节点之间的所有节点,不包含welcome,然后再入栈home节点。

navController.navigate("home") {
    popUpTo("welcome") { inclusive = true }
}

说明:清空当前节点到weclome节点之间的所有节点,包含welcome,然后再入栈home节点。

navController.navigate("home") {
    launchSingleTop = true
}

说明:如果栈顶是home节点,则不再重新入栈home节点,类似于Activity中的singleTop启动模式。

传递参数

  • 定义参数:在NavHost中修改,composable("two_page/{占位符1}/{占位符2}")
  • 传递参数:navController.navigate("two_page/参数1/参数2")
  • 获取参数:通过 NavBackStackEntry.arguments 提取参数。
@Composable
fun OnePage(navController: NavHostController) {
    BasePage("OnePage", navController) {
        // 传递参数
        navController.navigate("two_page/小明/18")
    }
}

@Composable
fun TwoPage(navController: NavHostController, name: String, age: String) {
    val context = LocalContext.current
    BasePage("TwoPage:${name}-${age}", navController) {
        Toast.makeText(context, "参数:${name}-${age}", Toast.LENGTH_SHORT).show()
    }
}

@Composable
fun MyNavigation() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "one_page"
    ) {
        composable("one_page") {            
            OnePage(navController)
        }
        composable("two_page/{name}/{age}") {
            // 接收参数
            TwoPage(
                navController,
                it.arguments?.getString("name") ?: "",
                it.arguments?.getString("age") ?: ""
            )
        }
    }
}

解析参数类型

上面的age其实是Int类型,但是用String类型接收到,不合理。

  • 通过 composable 中的 arguments 的 type 定义参数类型。
  • 再使用 getInt() 方法接收。
@Composable
fun TwoPage(navController: NavHostController, name: String, age: Int) {
    val context = LocalContext.current
    BasePage("TwoPage:${name}-${age}", navController) {
        Toast.makeText(context, "参数:${name}-${age}", Toast.LENGTH_SHORT).show()
    }
}

@Composable
fun MyNavigation() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "one_page"
    ) {
        composable("one_page") {
            OnePage(navController)
        }
        composable(
            "two_page/{name}/{age}",
            arguments = listOf(
                navArgument("name") { type = NavType.StringType },
                navArgument("age") { type = NavType.IntType }
            )
        ) {
            // 接收参数
            TwoPage(
                navController,
                it.arguments?.getString("name") ?: "",
                it.arguments?.getInt("age") ?: 0
            )
        }
    }
}

可选默认值参数

  • 传递参数:two_page?参数1={占位符2}?参数2={占位符2}。如果有参数则正常获取,如果没有参数则返回默认值
  • 定义参数默认值:通过 navArgument 中的 defaultValue 设置默认值。

默认值:

@Composable
fun OnePage(navController: NavHostController) {
    BasePage("OnePage", navController) {
        // 传递参数时
        navController.navigate("two_page?name=Tom?age=28")
    }
}

@Composable
fun OnePage(navController: NavHostController) {
    BasePage("OnePage", navController) {
        // 不传递参数时
        navController.navigate("two_page")
    }
}

@Composable
fun MyNavigation() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "one_page"
    ) {
        composable("one_page") {
            OnePage(navController)
        }
        composable(
            "two_page?name={name}?age={age}",
            arguments = listOf(
                navArgument("name") {
                    type = NavType.StringType
                    defaultValue = "未命名"
                },
                navArgument("age") {
                    type = NavType.IntType
                    defaultValue = 18
                }
            )
        ) {
            // 接收参数
            TwoPage(
                navController,
                it.arguments?.getString("name") ?: "",
                it.arguments?.getInt("age") ?: 0
            )
        }
    }
}

可选null值参数

  • 设置 nullable 为true表示支持null值。
@Composable
fun MyNavigation() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "one_page"
    ) {
        composable("one_page") {
            Log.e("TAG", "one_page")
            OnePage(navController)
        }
        composable(
            "two_page?name={name}?age={age}",
            arguments = listOf(
                navArgument("name") {
                    nullable = true
                },
                navArgument("age") {
                    nullable = true
                }
            )
        ) {
            // 接收参数
            TwoPage(
                navController,
                it.arguments?.getString("name") ?: "",
                it.arguments?.getString("age") ?: ""
            )
        }
    }
}

传递对象

传递对象的本质是将对象序列化为字符串,然后在接收字符串反序列化为对象。

data class Person(val name: String, val age: Int)
@Composable
fun OnePage(navController: NavHostController) {
    BasePage("OnePage", navController) {
        // 传递参数
        val personJson = Gson().toJson(Person("小黑", 60))
        navController.navigate("two_page?name=Tom?age=28/${personJson}")
    }
}

@Composable
fun TwoPage(navController: NavHostController, name: String, age: Int, person: Person) {
    val context = LocalContext.current
    BasePage("TwoPage:${name}-${age}-${person}", navController) {
        Toast.makeText(context, "参数:${name}-${age}-${person}", Toast.LENGTH_SHORT).show()
    }
}

@Composable
fun MyNavigation() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "one_page"
    ) {
        composable("one_page") {
            OnePage(navController)
        }
        composable(
            "two_page?name={name}?age={age}/{person}",
            arguments = listOf(
                navArgument("name") {
                    type = NavType.StringType
                    defaultValue = "未命名"
                },
                navArgument("age") {
                    type = NavType.StringType
                    defaultValue = "0"
                },
                navArgument("person") {
                    type = NavType.StringType
                }
            )
        ) {
            // 接收参数
            val personJson = it.arguments?.getString("person") ?: ""
            val person = Gson().fromJson(personJson, Person::class.java)
            TwoPage(
                navController,
                it.arguments?.getString("name") ?: "",
                it.arguments?.getInt("age") ?: 0,
                person
            )
        }
    }
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值