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

Android键盘显隐时如何让Compose对话框重新组合?

解决Compose登录对话框键盘关闭后未自动展开的问题

问题根源是键盘状态变化时未触发Compose重组,导致对话框没有重新测量高度。可以通过监听输入法(IME)的可见性状态,让Compose感知到变化并触发重组。

具体实现步骤

  1. 监听IME可见性状态:在Dialog的Composable中,利用LocalWindowInsets获取输入法的可见性状态,通过derivedStateOf让Compose监听该状态的变化。
  2. 触发重组:将IME可见性状态作为Composable的依赖项,确保键盘状态变化时触发UI重组,让对话框重新计算高度。

修改后的代码示例

fun LoginDialog(
    onDismissRequest: () -> Unit,
    context: Context
) {
    val theme by currentTheme.collectAsMutableState()
    val error by rememberSaveable { mError }
    var emailError by rememberSaveable { mutableStateOf(context.getString(R.string.empty_error_text)) }
    var passwordError by rememberSaveable { mutableStateOf(context.getString(R.string.empty_error_text)) }
    var email by rememberSaveable { mutableStateOf("") } // 修正:改为mutableStateOf,确保输入变化触发重组
    var password by rememberSaveable { mutableStateOf("") } // 修正:改为mutableStateOf

    // 监听输入法可见性变化
    val imeInsets = LocalWindowInsets.current.ime
    val isImeVisible by remember { derivedStateOf { imeInsets.isVisible } }

    Dialog(
        onDismissRequest = onDismissRequest,
        properties = DialogProperties(dismissOnClickOutside = false)
    ) {
        Surface(
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentHeight(),
            shape = RoundedCornerShape(size = 10.dp)
        ) {
            Column(modifier = Modifier.padding(16.dp)) {
                Row(
                    modifier = Modifier.fillMaxWidth()
                ) {
                    Image(
                        modifier = verticalGradientModifier(theme).size(25.dp),
                        painter = painterResource(id = R.mipmap.icons8_login_125px),
                        contentDescription = stringResource(R.string.log_in_online)
                    )
                    Text(
                        modifier = horizontalGradientModifier(theme)
                            .align(CenterVertically)
                            .padding(start = 5.dp),
                        text = stringResource(R.string.log_in_online),
                        fontSize = 16.sp,
                        fontWeight = FontWeight.Bold
                    )
                }
                // 引用isImeVisible,确保键盘状态变化时触发重组
                val _ = isImeVisible
                Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
                    if (error.isNotEmpty()) {
                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(5.dp)
                                .border(1.dp, Color.Red, RoundedCornerShape(10))
                        ) {
                            Text(
                                modifier = Modifier.padding(5.dp),
                                text = error,
                                color = Color.Red
                            )
                        }
                    }
                    InputView(
                        title = stringResource(R.string.email_label),
                        description = stringResource(R.string.login_email_description),
                        icon = R.mipmap.icons8_mail_125px,
                        error = emailError,
                        important = true
                    ) {
                        email = it
                        emailError = if (it.isNotEmpty()) {
                            ""
                        } else {
                            context.getString(R.string.empty_error_text)
                        }
                    }
                    InputView(
                        title = stringResource(R.string.label_password),
                        description = stringResource(R.string.login_password_description),
                        icon = R.mipmap.icons8_password_125px,
                        error = passwordError,
                        inputType = KeyboardType.Password,
                        important = true
                    ) {
                        password = it
                        passwordError = if (it.isNotEmpty()) {
                            ""
                        } else {
                            context.getString(R.string.empty_error_text)
                        }
                    }
                    Row(
                        modifier = Modifier
                            .align(CenterHorizontally)
                            .padding(10.dp)
                    ) {
                        TextButton(
                            modifier = Modifier
                                .padding(5.dp)
                                .border(
                                    width = 1.dp,
                                    brush = horizontalGradientBrush(theme),
                                    shape = RoundedCornerShape(percent = 10)
                                ),
                            enabled = passwordError.isEmpty() && emailError.isEmpty(),
                            onClick = {
                                Repository.execute {
                                    Repository.login(email, password) { success, _ ->
                                        if (success) {
                                            onDismissRequest()
                                        } else {
                                            mError.value = "Either email or password was wrong."
                                        }
                                    }
                                }
                            }) {
                            Image(
                                modifier = verticalGradientModifier(theme).size(25.dp),
                                painter = painterResource(id = R.mipmap.icons8_login_125px),
                                contentDescription = stringResource(R.string.title_login)
                            )
                            Text(
                                modifier = horizontalGradientModifier(theme).padding(start = 5.dp),
                                text = stringResource(R.string.title_login)
                            )
                        }
                        Text(
                            modifier = horizontalGradientModifier(theme)
                                .padding(5.dp)
                                .align(CenterVertically),
                            text = "or"
                        )
                        TextButton(
                            modifier = Modifier
                                .padding(5.dp)
                                .border(
                                    width = 1.dp,
                                    brush = horizontalGradientBrush(theme),
                                    shape = RoundedCornerShape(percent = 10)
                                ),
                            onClick = {
                                //open Sign-In dialog
                            }) {
                            Image(
                                modifier = verticalGradientModifier(theme).size(25.dp),
                                painter = painterResource(id = R.mipmap.icons8_create_125px),
                                contentDescription = stringResource(R.string.sign_in)
                            )
                            Text(
                                modifier = horizontalGradientModifier(theme).padding(start = 5.dp),
                                text = stringResource(R.string.sign_in)
                            )
                        }
                    }
                }
            }
        }
    }
}

关键说明

  • IME可见性监听:通过LocalWindowInsets.current.ime.isVisible获取键盘状态,并用derivedStateOf包装,确保状态变化能被Compose感知。
  • 触发重组:在Column中引用isImeVisible变量(即使只是赋值给一个无用变量),让Compose将该状态作为重组依赖,键盘状态变化时自动触发UI重新测量布局。
  • 额外修正:将email和password改为mutableStateOf,确保输入内容变化时能正确触发相关UI更新(比如按钮启用状态)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 23:24:57