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() 转换对象,传递值
相关推荐
氦客8 天前
Android Compose 显示底部对话框 (ModalBottomSheet),实现类似BottomSheetDialog的效果
android·dialog·ui·compose·modal·bottomsheet·底部对话框
小林爱23 天前
【Compose multiplatform教程06】用IDEA编译Compose Multiplatform常见问题
android·java·前端·kotlin·intellij-idea·compose·多平台
小林爱25 天前
【Compose multiplatform教程12】【组件】Box组件
前端·kotlin·android studio·框架·compose·多平台
俺不理解1 个月前
Android Compose 悬浮窗
android·生命周期·compose·悬浮窗
H.ZWei1 个月前
鸿蒙ZRouter动态路由框架—服务路由
harmonyos·鸿蒙·navigation·router
特立独行的猫a1 个月前
HarmonyOS NEXT的Navigation,跳转子页面后底部Tab不隐藏问题解决
开发语言·前端·javascript·harmonyos·navigation
大熊猫侯佩2 个月前
SwiftUI 列表(或 Form)子项中的 Picker 引起导航无法跳转的原因及解决
list·swiftui·form·列表·navigation·导航·picker
梁辰兴2 个月前
Android Studio 使用插件Database Navigation 连接 sqlite数据库
数据库·sqlite·android studio·database·navigation·plugins
许三多20202 个月前
Compose Navigation快速入门
compose·navigation·compose 导航
howard20052 个月前
鸿蒙实战:页面跳转传参
harmonyos·跳转·router·传参