Compose | UI组件(十四) | Navigation-Data - 页面导航传递数据

文章目录

前言

在 Compose 中使用 Navigation 组件进行页面跳转时,可以使用 NavController 和 NavHost 来传递参数。

传参流程

  1. 使用 NavController 传递参数:

NavController 是 Navigation 组件的核心类,用于控制页面导航。你可以在 NavController 中使用

navigate() 方法传递参数。这些参数可以在目标页面中通过参数名称获取并使用。

例如:

kotlin 复制代码
navController.navigate("SecondScreen") {  
    // 传递参数  
    arguments = remember { mutableStateOf("key") }  
    arguments?.putString("key", "value")  
}

在目标页面中,可以通过 arguments 参数获取传递的参数:

kotlin 复制代码
val value = arguments?.getString("key") ?: "default value"
  1. 使用 NavHost 传递参数:

在 NavHost 中,可以使用 composable() 函数定义导航路径和参数。在 composable()

函数中,可以指定传递的参数和接收参数的方法。

例如:

kotlin 复制代码
NavHost(navController = navController, startDestination = "MainScreen") {  
    composable("MainScreen") { MainScreen(arguments = listOf("value1", "value2")) }  
    composable("SecondScreen") { SecondScreen(arguments = listOf("value3", "value4")) }  
}

在目标页面中,可以通过 arguments 参数获取传递的参数:

kotlin 复制代码
val values = arguments[0] + arguments[1] // value1value2 for MainScreen, value3value4 for SecondScreen

这些是在 Compose 中使用 Navigation 组件进行参数传递的一些常见方法。具体实现可能因不同的平台、框架或技术而有所差异。

实例说明

下面使用登录页面传入用户名和密码,到详情页面,做为讲解案例

普通方式传值

就是通过 (状态)State 控制变量的传值

定义接受参数格式
kotlin 复制代码
object Detail:Screen(route = "$DETAIL?id={id},name={name},password={password}")

注:$DETAIL?id={id},name={name},password={password} 改为 $DETAIL/id={id},name={name},password={password}。将 ? 改为 / ,如果没有传值,程序就会崩溃,/ 默认是必填的,? 默认是选填的

定义接受参数类型
kotlin 复制代码
composable(route = Screen.Detail.route,
           arguments = listOf(
                navArgument(DETAIL_ARGUMENT_ID){
                    type = NavType.IntType
                    defaultValue = 0
                },
                navArgument(DETAIL_ARGUMENT_NAME){
                    type = NavType.StringType
                    defaultValue = "name is null"
                },
                navArgument(DETAIL_ARGUMENT_PASSWORD){
                    type = NavType.StringType
                    defaultValue = "password is null"
                }
           )
)

const val DETAIL_ARGUMENT_ID       = "id"
const val DETAIL_ARGUMENT_NAME     = "name"
const val DETAIL_ARGUMENT_PASSWORD = "password"
获取参数
kotlin 复制代码
composable(route = Screen.Detail.route,
           ...){navBackStackEntry ->
	    val id    = navBackStackEntry.arguments?.getInt("id") ?: 0
	    val name  = navBackStackEntry.arguments?.getString("name") ?: ""
	    val password   = navBackStackEntry.arguments?.getString("password") ?: ""
	    DetailScreen(id,name,password,navController = navController)
}
传入参数
kotlin 复制代码
object Detail:Screen(route = "..."){

    fun passIdAndName(id:Int= 0,name:String="tanZuAi",password:String="tanZuAi123"):String{
        return "$DETAIL?id=${id},name=${name},password=${password}"
    }
}

navController.navigate(Screen.Detail.passIdAndName())
传参和接受参数效果图

至此,基本的传参,就已经可以实现了

结合 ViewModel 传递参数

就是通过结合 ViewModel 传参

定义ViewModel

LoginViewModel.kt

kotlin 复制代码
class LoginViewModel: ViewModel(){
    var nameText by mutableStateOf("")

    fun onTextChanged(newString:String){
        nameText = newString
    }
}
kotlin 复制代码
navigation(startDestination = Screen.Login.route,route = AUTHENTICATION_ROUTE){
		   composable(route = Screen.Login.route){
		        val loginViewModel = viewModel<LoginViewModel>()
		        LoginScreen(loginViewModel,navController  = navController)
		    }
		    composable(route = Screen.Signup.route){
		        SignUpScreen(navController = navController)
		    }
}
传入输入框中的值,并且跳转传值

LoginScreen.kt

kotlin 复制代码
//定义ViewModel 参数
fun LoginScreen(loginViewModel:LoginViewModel = viewModel(), navController: NavController)

  //注释掉状态定义的变量值
//var textName by remember { mutableStateOf("") }
//监听输入框的值,并且改变viewmodel变量的值
OutlinedTextField(value = loginViewModel.nameText,
    onValueChange = {
        loginViewModel.onTextChanged(it)
    },
    label = { Text(text = stringResource(id = R.string.app_user_name)) },
    modifier = Modifier.fillMaxWidth()
)

//传值给name
navController.navigate(Screen.Detail.passIdAndName(name = loginViewModel.nameText))
获取值

Screen.kt

kotlin 复制代码
object Detail:Screen(route = "$DETAIL?id={id},name={name},password={password}"){
    fun passIdAndName(id:Int= 0,name:String="tanZuAi",password:String="tanZuAi123"):String{
        return "$DETAIL?id=${id},name=${name},password=${password}"
    }
}

HomeNavGraph.kt

kotlin 复制代码
val name  = navBackStackEntry.arguments?.getString("name") ?: ""

DetailScreen(id,name,password,navController = navController)

DetailScreen.kt

kotlin 复制代码
Text(modifier = Modifier.clickable {},
           text  = "Detail_Name: $name" ,
           color = Color.Red,
           style = MaterialTheme.typography.bodyLarge)

至此,结合 ViewModel 传值流程已经讲完了

Parcelable 传递参数

通过Parcelable传递一个对象数据

定义一个数据类
kotlin 复制代码
@Parcelize
data class EmailModel(val id:Int,var name:String,var password:String):Parcelable
自定义定义一个通用的NavType
kotlin 复制代码
inline fun <reified T : Parcelable> createParcelableNavType(isNullableAllowed: Boolean = false): NavType<T> {
    return object : NavType<T>(isNullableAllowed) {

        override val name: String
            get() = "SupportParcelable"

        override fun get(bundle: Bundle, key: String): T? {  //从Bundle中检索 Parcelable类型
            return bundle.getParcelable(key)
        }

        override fun parseValue(value: String): T {  //定义传递给 String 的 Parsing 方法
            return Gson().fromJson(value, T::class.java)
        }

        override fun put(bundle: Bundle, key: String, value: T) {  //作为 Parcelable 类型添加到 Bundle
            bundle.putParcelable(key, value)
        }

    }
}

navArgument("jsonParcelable"){
    type = createParcelableNavType<EmailModel>()
}
设置一个接受参数的占位符
kotlin 复制代码
object Detail:Screen(route = "$DETAIL?key={jsonParcelable}")
传递参数
kotlin 复制代码
fun passIdAndName(id:Int= 0,name:String="tanZuAi",password:String="tanZuAi123"):String{
    val jsonParcelable = Gson().toJson(EmailModel(id,name, password))
    return "$DETAIL?key=${Uri.encode(jsonParcelable)}"
}
接收参数
kotlin 复制代码
val emailModel = navBackStackEntry.arguments?.getParcelable<EmailModel>("jsonParcelable")

emailModel?.apply {
    DetailScreen(id,name,password,navController = navController)
}

注:至此,通过 Parcelable 传递对象数据就讲完了

总结

  1. 普通方式传值:$DETAIL?id={id},name={name},password={password}
  2. ViewModel传值:继承 ViewModel() 类,在类中定义状态变量,通过监听变量值变化,获取变量值
  3. Parcelable传值:通过 Gson().toJson() 转换对象,传递值
相关推荐
tangweiguo030519872 小时前
在 Jetpack Compose 中实现 iOS 风格输入框
android·compose
tangweiguo030519878 天前
Android Compose 权限申请完整指南
compose
tangweiguo0305198713 天前
androd的XML页面 跳转 Compose Activity 卡顿问题
compose
tangweiguo0305198713 天前
iOS 风格弹框组件集 (Compose版)
compose
tangweiguo0305198713 天前
Android Material Design 3 主题配色终极指南:XML 与 Compose 全解析
compose
tangweiguo0305198714 天前
Android Compose 中获取和使用 Context 的完整指南
android·compose
tangweiguo0305198716 天前
Jetpack Compose 自定义组件完全指南
compose
tangweiguo0305198717 天前
打破界限:Android XML与Jetpack Compose深度互操作指南
android·kotlin·compose
wangz7624 天前
kotlin,jetpack compose 最简导航(navigation)案例学习
kotlin·navigation·jetpack compose
wavky1 个月前
零经验选手,Compose 一天开发一款小游戏!
compose