Composable中如何点击按钮关闭已展开的不可聚焦DropdownMenu
问题根源在于PopupProperties(focusable = false)会让DropdownMenu不消费点击事件,导致点击展开按钮时,事件会先后触发onDismissRequest和按钮的onClick:前者先把expanded设为false,后者又将其设为true,最终菜单无法关闭。
解决方案:用标志位区分按钮点击与外部点击
添加一个布尔标志位记录是否是按钮触发的操作,让onDismissRequest仅在非按钮点击时执行关闭逻辑:
var expanded by remember { mutableStateOf(false) } // 记录是否为按钮点击触发的操作 val isButtonClick by remember { mutableStateOf(false) } Box() { IconButton(onClick = { isButtonClick = true // 直接切换展开状态,而非强制设为true expanded = !expanded }) { Icon(Icons.Default.ArrowDropDown, contentDescription = "展开菜单") } DropdownMenu( expanded = expanded, onDismissRequest = { // 仅当不是按钮点击时,才执行关闭逻辑 if (!isButtonClick) { expanded = false } // 重置标志位,避免影响后续操作 isButtonClick = false }, properties = PopupProperties(focusable = false) ) { DropdownMenuItem(onClick = { expanded = false }) { Text("菜单选项1") } DropdownMenuItem(onClick = { expanded = false }) { Text("菜单选项2") } } }
另一种方案:拦截按钮点击事件
通过pointerInput拦截按钮的点击事件,阻止事件传递到DropdownMenu的onDismissRequest,这样就不会触发重复的状态修改:
var expanded by remember { mutableStateOf(false) } Box() { // 用Box替代IconButton,直接通过pointerInput处理点击 Box( modifier = Modifier .pointerInput(expanded) { detectTapGestures(onTap = { expanded = !expanded // 消费所有事件,阻止传递到DropdownMenu consumeAllEvents() }) } .padding(16.dp) // 模拟IconButton的内边距 ) { Icon(Icons.Default.ArrowDropDown, contentDescription = "展开菜单") } DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false }, properties = PopupProperties(focusable = false) ) { DropdownMenuItem(onClick = { expanded = false }) { Text("菜单选项1") } } }
两种方案都能保留focusable=false以避免键盘收起,同时解决点击按钮无法关闭菜单的问题。
内容的提问来源于stack exchange,提问作者mpellegr
相关产品推荐
相关产品推荐

