Compose AlertDialog点击按钮无法关闭问题求助
我有一个Compose Dialog,点击按钮时无法关闭。我认为问题出在代码里的if语句,但我需要在!parentUiState.showInAppFeedback这个条件下让openDialog的值为true,请问有什么解决办法?
我的代码
@Composable fun PopupWindowDialog( parentUiState: ParentHomeUiState, ) { val openDialog = remember { mutableStateOf(false) } var sliderPosition by remember { mutableStateOf(0f) } if (!parentUiState.showInAppFeedback){ openDialog.value = true } val recommend = sliderPosition.toInt() Column( ) { Box { if (openDialog.value) { Dialog( onDismissRequest = { openDialog.value = false }, properties = DialogProperties(), ){ Box( Modifier .fillMaxWidth() .fillMaxHeight() //.padding(vertical = 70.dp, horizontal = 10.dp) .padding(vertical = 70.dp ) .background(Color.White, RoundedCornerShape(10.dp)) //.border(1.dp, color = Color.Black, RoundedCornerShape(20.dp)) .border(1.dp, color = Color.White, RoundedCornerShape(20.dp)) ) { Button( modifier = Modifier .fillMaxWidth() .padding(10.dp), onClick = { openDialog.value = !openDialog.value } ) { Text( text = "¡Contesta y gana +20 puntos!", style = MaterialTheme.typography.subtitle2, fontWeight = FontWeight.Bold, modifier = Modifier.padding(3.dp)) } } } } } } }
问题原因
你当前的代码存在一个关键问题:每次Composable重组时,只要!parentUiState.showInAppFeedback为true,openDialog.value就会被强制设置为true。哪怕你点击按钮把openDialog.value改成false,重组后这条if语句会立刻将其改回true,导致Dialog永远无法关闭。
直接在Composable根节点修改状态值是错误的做法,因为重组会频繁触发,覆盖用户的手动操作。
解决方案
方案1:仅在条件变化时触发一次Dialog打开
如果你只需要在parentUiState.showInAppFeedback从true变为false时打开一次Dialog,后续允许用户手动关闭且不会被强制重新打开,用LaunchedEffect监听状态变化:
@Composable fun PopupWindowDialog( parentUiState: ParentHomeUiState, ) { val openDialog = remember { mutableStateOf(false) } var sliderPosition by remember { mutableStateOf(0f) } // 用LaunchedEffect替代直接赋值,仅在showInAppFeedback变化时执行 LaunchedEffect(parentUiState.showInAppFeedback) { if (!parentUiState.showInAppFeedback) { openDialog.value = true } } val recommend = sliderPosition.toInt() Column( ) { Box { if (openDialog.value) { Dialog( onDismissRequest = { openDialog.value = false }, properties = DialogProperties(), ){ // ... 原有Dialog内容不变 Button( modifier = Modifier .fillMaxWidth() .padding(10.dp), onClick = { openDialog.value = false } ) { Text( text = "¡Contesta y gana +20 puntos!", style = MaterialTheme.typography.subtitle2, fontWeight = FontWeight.Bold, modifier = Modifier.padding(3.dp)) } } } } } }
说明:LaunchedEffect会在parentUiState.showInAppFeedback的值发生变化时执行一次,不会在每次重组时重复覆盖openDialog的值,用户点击关闭后Dialog就会保持关闭状态,直到parentUiState.showInAppFeedback再次变为true后又变回false。
方案2:允许用户临时关闭,条件满足时自动重新打开
如果你需要在!parentUiState.showInAppFeedback持续成立时,Dialog保持打开,但允许用户临时关闭(后续若条件仍满足则重新弹出),可以增加一个状态记录用户是否手动关闭:
@Composable fun PopupWindowDialog( parentUiState: ParentHomeUiState, ) { val openDialog = remember { mutableStateOf(false) } val manuallyClosed = remember { mutableStateOf(false) } // 新增状态记录手动关闭 var sliderPosition by remember { mutableStateOf(0f) } LaunchedEffect(parentUiState.showInAppFeedback, manuallyClosed.value) { // 只有条件满足且用户未手动关闭时,才打开Dialog if (!parentUiState.showInAppFeedback && !manuallyClosed.value) { openDialog.value = true } } val recommend = sliderPosition.toInt() Column( ) { Box { if (openDialog.value) { Dialog( onDismissRequest = { openDialog.value = false manuallyClosed.value = true // 标记为手动关闭 }, properties = DialogProperties(), ){ // ... 原有Dialog内容不变 Button( modifier = Modifier .fillMaxWidth() .padding(10.dp), onClick = { openDialog.value = false manuallyClosed.value = true // 标记为手动关闭 } ) { Text( text = "¡Contesta y gana +20 puntos!", style = MaterialTheme.typography.subtitle2, fontWeight = FontWeight.Bold, modifier = Modifier.padding(3.dp)) } } } } } }
说明:用户手动关闭Dialog后,manuallyClosed会被设为true,此时即使!parentUiState.showInAppFeedback仍成立,Dialog也不会自动打开。只有当parentUiState.showInAppFeedback变为true后又变回false时,可根据业务逻辑决定是否重置manuallyClosed状态。
内容的提问来源于stack exchange,提问作者user10625391

