Jetpack Compose:实现可编辑、动态过滤且不阻塞输入的ExposedDropDownMenuBox
解决Jetpack Compose中动态过滤下拉菜单的输入阻塞问题
要实现输入时实时过滤下拉列表、且菜单展开时不阻塞输入,同时保留Material 3 ExposedDropdownMenuBox的UI样式,可以通过以下方案实现:
核心思路是复用ExposedDropdownMenuBox的布局容器和文本框装饰,将默认的ExposedDropdownMenu替换为可自定义焦点行为的DropdownMenu,并设置PopupProperties(focusable = false),这样既保留了MD3的原生UI风格,又能让输入框在菜单展开时持续接收输入。
完整代码示例
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.ImeAction @OptIn(ExperimentalMaterial3Api::class) @Composable fun DynamicFilterDropdown() { // 原始选项列表 val allOptions = remember { mutableStateListOf("Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig") } // 输入框文本状态 var inputText by remember { mutableStateOf("") } // 菜单展开状态 var expanded by remember { mutableStateOf(false) } // 过滤后的选项列表 val filteredOptions = remember(inputText) { allOptions.filter { it.contains(inputText, ignoreCase = true) } } ExposedDropdownMenuBox( expanded = expanded, onExpandedChange = { expanded = !expanded } ) { TextField( value = inputText, onValueChange = { inputText = it // 输入时自动展开菜单 expanded = true }, modifier = Modifier .fillMaxWidth() .menuAnchor(), // 必须添加此修饰符关联菜单 label = { Text("选择或输入选项") }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, colors = ExposedDropdownMenuDefaults.textFieldColors(), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { expanded = false }) ) // 替换默认的ExposedDropdownMenu为DropdownMenu,设置焦点不抢占 DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false }, properties = androidx.compose.ui.window.PopupProperties(focusable = false) ) { filteredOptions.forEach { option -> DropdownMenuItem( text = { Text(option) }, onClick = { inputText = option expanded = false } ) } } } }
关键细节说明
- 复用ExposedDropdownMenuBox的UI:通过
menuAnchor()修饰符将TextField与菜单关联,保留了MD3中下拉菜单文本框的样式(包括尾部箭头、输入框装饰)。 - 禁用菜单焦点抢占:使用
DropdownMenu并设置PopupProperties(focusable = false),让菜单不再抢占输入焦点,输入框在菜单展开时仍能接收用户输入。 - 实时过滤逻辑:通过
remember(inputText)监听输入文本变化,动态生成过滤后的选项列表,确保输入时菜单内容实时更新。 - 交互优化:输入时自动展开菜单,点击选项后填充文本并收起菜单,点击尾部箭头可手动切换菜单状态,按下Done键收起菜单,符合用户预期的交互逻辑。
内容的提问来源于stack exchange,提问作者tariqebadi
相关产品推荐
相关产品推荐

