Android键盘显隐时如何让Compose对话框重新组合?
解决Compose登录对话框键盘关闭后未自动展开的问题
问题根源是键盘状态变化时未触发Compose重组,导致对话框没有重新测量高度。可以通过监听输入法(IME)的可见性状态,让Compose感知到变化并触发重组。
具体实现步骤
- 监听IME可见性状态:在Dialog的Composable中,利用
LocalWindowInsets获取输入法的可见性状态,通过derivedStateOf让Compose监听该状态的变化。 - 触发重组:将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
相关产品推荐
相关产品推荐

