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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:45:00