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

Composable点击按钮不重组:登录页SnackBar仅首次生效

问题分析与解决方案

问题根源

你的SnackBar仅首次触发有效,核心原因是shouldShowSnackBar状态的更新逻辑有缺陷:

  • 首次点击按钮时,shouldShowSnackBar从false变为true,触发LaunchEffect执行并显示SnackBar。
  • 但SnackBar显示完毕后,shouldShowSnackBar依然保持true,后续再次点击按钮时,即使用户名/密码仍为空,该状态值没有发生变化,导致LaunchEffect的key未更新,因此不会再次触发SnackBar。

修复方案1:重置状态变量

在LaunchEffect中,SnackBar显示完成后手动将shouldShowSnackBar重置为false,确保下次点击按钮时状态能再次从false变为true,触发LaunchEffect:

@Composable
fun Login() {
    var username by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }
    val scaffoldState = rememberScaffoldState()
    var shouldShowSnackBar by remember { mutableStateOf(false) }

    println("LoginScreen")

    LaunchedEffect(key1 = shouldShowSnackBar) {
        if (shouldShowSnackBar) {
            println("ShouldShowSnackBar")
            scaffoldState.snackbarHostState.showSnackbar(
                message = "Please enter a username and password",
                duration = SnackbarDuration.Short
            )
            // SnackBar显示完成后重置状态
            shouldShowSnackBar = false
        }
    }

    Scaffold(scaffoldState = scaffoldState) {
        Column(modifier = Modifier.fillMaxWidth()) {
            OutlinedTextField(
                label = { Text(text = "Username") },
                value = username,
                onValueChange = { username = it }
            )

            OutlinedTextField(
                label = { Text(text = "Password") },
                value = password,
                onValueChange = { password = it },
                visualTransformation = PasswordVisualTransformation()
            )

            OutlinedButton(
                modifier = Modifier.fillMaxWidth(),
                onClick = {
                    shouldShowSnackBar = username.isEmpty() || password.isEmpty()
                    println("Button pressed: $shouldShowSnackBar")
                }
            ) {
                Text(text = "Submit")
            }
        }
    }
}

修复方案2:直接在点击事件中处理(更简洁)

使用rememberCoroutineScope获取协程作用域,直接在按钮点击事件中判断并显示SnackBar,无需额外状态变量,每次点击都会触发协程执行:

@Composable
fun Login() {
    var username by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }
    val scaffoldState = rememberScaffoldState()
    val coroutineScope = rememberCoroutineScope()

    println("LoginScreen")

    Scaffold(scaffoldState = scaffoldState) {
        Column(modifier = Modifier.fillMaxWidth()) {
            OutlinedTextField(
                label = { Text(text = "Username") },
                value = username,
                onValueChange = { username = it }
            )

            OutlinedTextField(
                label = { Text(text = "Password") },
                value = password,
                onValueChange = { password = it },
                visualTransformation = PasswordVisualTransformation()
            )

            OutlinedButton(
                modifier = Modifier.fillMaxWidth(),
                onClick = {
                    if (username.isEmpty() || password.isEmpty()) {
                        coroutineScope.launch {
                            scaffoldState.snackbarHostState.showSnackbar(
                                message = "Please enter a username and password",
                                duration = SnackbarDuration.Short
                            )
                        }
                    }
                }
            ) {
                Text(text = "Submit")
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:20:27