You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中如何校验跨页面多个TextField邮箱值一致

跨页面邮箱一致性校验实现方案

你现有项目已接入Hilt共享ViewModel,优先选择状态收敛到ViewModel统一管理的方案,改动最小、稳定性最高,不需要额外处理传参序列化、状态丢失问题。

方案实现步骤

1. 修复现有代码的基础问题

首先修正ScreenA的变量名错误:你在ScreenA中定义的输入状态名为email,下方输入框却引用了未定义的emailState,会直接导致编译失败,后续统一替换为ViewModel中的全局状态即可。
另外你onSignUpEmail方法中查询Firestore时使用了未定义的email变量,后续替换为方法入参即可。

2. 扩展ViewModel的状态与校验逻辑

把三个输入框的状态、校验规则全部收敛到ViewModel中,避免每个页面单独维护本地状态导致不同步:

// 在MyViewModel中增加以下代码
// ScreenA输入的初始邮箱
val screenAEmail = mutableStateOf(TextFieldValue())
// ScreenB的邮箱输入
val screenBEmail = mutableStateOf(TextFieldValue())
// ScreenB的确认邮箱输入
val screenBConfirmEmail = mutableStateOf(TextFieldValue())
// 校验错误信息
val emailCheckError = mutableStateOf<String?>(null)

// 从ScreenA跳转到ScreenB前调用,同步初始值
fun prepareNavigateToScreenB() {
    val inputEmail = screenAEmail.value.text.trim()
    if (inputEmail.isEmpty()) {
        emailCheckError.value = "请输入邮箱后再继续"
        return
    }
    // 给ScreenB两个输入框赋默认值,和ScreenA保持一致
    screenBEmail.value = screenAEmail.value
    screenBConfirmEmail.value = screenAEmail.value
    emailCheckError.value = null
}

// 实时校验三个邮箱值是否一致
fun checkEmailConsistency(): Boolean {
    val originEmail = screenAEmail.value.text.trim()
    val inputBEmail = screenBEmail.value.text.trim()
    val inputConfirmEmail = screenBConfirmEmail.value.text.trim()
    return when {
        inputBEmail != originEmail -> {
            emailCheckError.value = "邮箱需与上一页输入内容一致"
            false
        }
        inputConfirmEmail != originEmail -> {
            emailCheckError.value = "确认邮箱需与上一页输入内容一致"
            false
        }
        else -> {
            emailCheckError.value = null
            true
        }
    }
}

3. 修改ScreenA代码

移除本地remember的输入状态,直接使用ViewModel中的全局状态,跳转前做前置校验:

@Composable
fun ScreenA(
    navController: NavController,
    model: MyViewModel
) {
    Column(
        Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        OutlinedTextField(
            value = model.screenAEmail.value,
            colors = TextFieldDefaults.textFieldColors(
                backgroundColor = white,
                focusedIndicatorColor = Grey,
                unfocusedIndicatorColor = Grey,
                focusedLabelColor = Grey,
                unfocusedLabelColor = Grey,
                cursorColor = custom,
                textColor = custom,
            ),
            onValueChange = { model.screenAEmail.value = it },
            label = { Text(text = "Email") },
            placeholder = { Text(text = "Email") },
            singleLine = true,
            modifier = Modifier.fillMaxWidth(0.8f)
        )
        // 跳转按钮
        Button(
            onClick = {
                model.prepareNavigateToScreenB()
                if (model.emailCheckError.value == null) {
                    navController.navigate("screenB")
                }
            },
            modifier = Modifier.padding(top = 16.dp)
        ) {
            Text("下一步")
        }
        // 错误提示
        model.emailCheckError.value?.let {
            Text(text = it, color = Color.Red, modifier = Modifier.padding(top = 8.dp))
        }
    }
}

4. 修改ScreenB代码

同样使用ViewModel中的全局状态,输入时实时触发校验,提交前做最终一致性判断:

@Composable
fun ScreenB(
    navController: NavController,
    model: MyViewModel
) {
    Column(
        Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        OutlinedTextField(
            value = model.screenBEmail.value,
            colors = TextFieldDefaults.textFieldColors(
                backgroundColor = white,
                focusedIndicatorColor = Grey,
                unfocusedIndicatorColor = Grey,
                focusedLabelColor = Grey,
                unfocusedLabelColor = Grey,
                cursorColor = custom,
                textColor = custom,
            ),
            onValueChange = {
                model.screenBEmail.value = it
                model.checkEmailConsistency()
            },
            label = { Text(text = "E-mail") },
            singleLine = true,
            modifier = Modifier.fillMaxWidth(0.8f),
            isError = model.emailCheckError.value != null
        )

        OutlinedTextField(
            value = model.screenBConfirmEmail.value,
            colors = TextFieldDefaults.textFieldColors(
                backgroundColor = white,
                focusedIndicatorColor = Grey,
                unfocusedIndicatorColor = Grey,
                focusedLabelColor = Grey,
                unfocusedLabelColor = Grey,
                cursorColor = custom,
                textColor = custom,
            ),
            onValueChange = {
                model.screenBConfirmEmail.value = it
                model.checkEmailConsistency()
            },
            label = { Text(text = "Confirm E-mail") },
            placeholder = { Text(text = "Confirm E-mail") },
            singleLine = true,
            modifier = Modifier.fillMaxWidth(0.8f),
            isError = model.emailCheckError.value != null
        )
        // 错误提示
        model.emailCheckError.value?.let {
            Text(text = it, color = Color.Red, modifier = Modifier.padding(top = 8.dp))
        }
        // 提交按钮
        Button(
            onClick = {
                if (model.checkEmailConsistency()) {
                    model.onSignUpEmail(
                        emailState = model.screenBEmail.value.text.trim(),
                        confirmEmailState = model.screenBConfirmEmail.value.text.trim()
                    )
                }
            },
            modifier = Modifier.padding(top = 16.dp),
            enabled = model.emailCheckError.value == null
        ) {
            Text("完成注册")
        }
    }
}

可选优化

  • 如果业务要求ScreenB的邮箱不允许用户修改,直接给两个OutlinedTextField加上readOnly = true属性,从根源上避免输入不一致的问题
  • 备选方案:如果不想把状态存在ViewModel中,也可以在ScreenA跳转时将邮箱字符串作为导航参数传递给ScreenB,ScreenB拿到参数后给输入框赋初始值,校验时直接对比传入的参数值即可。但这种方案需要处理路由参数的序列化适配,不如共享ViewModel方案简便。

内容的提问来源于stack exchange,提问作者SpaceDevs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 12:33:34