Jetpack Compose 中的可编辑动态 ExusedDropDownMenuBox

tar*_*adi 7 android-jetpack-compose android-compose-textfield android-jetpack-compose-material3 android-compose-exposeddropdown

我试图让这个下拉菜单变得动态。当我在文本字段中输入内容时,我希望列表能够更新(根据用户输入的内容进行过滤),并且用户可以从过滤后的下拉列表中进行选择。

我在这里检查了开发文档中的示例代码 https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#ExposeDropdownMenuBox(kotlin.Boolean,kotlin.Function1,androidx.compose .ui.修饰符,kotlin.Function1)

我发现材质 3 下拉菜单在展开状态下会阻止用户输入。如果用户开始输入并且我们说

onValueChange = { 
        selectedOptionText = it
        expanded = true
}
Run Code Online (Sandbox Code Playgroud)

用户被阻止进一步输入,因为展开的 ExposedDropdownMenu 会阻止用户输入

如何使文本字段动态打开下拉菜单,并根据用户输入更新列表?并且列表项是可选的

为了添加更多上下文,我知道如果我们说properties = PopupProperties(focusable = false),DropdownMenu不会阻止用户输入

DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
            properties = PopupProperties(focusable = false)
        )
Run Code Online (Sandbox Code Playgroud)

但 UI 行为并不相同。我正在寻找 DropdownMenuBox 行为 DropdownMenu 属性 = PopupProperties(focusable = false)

tar*_*adi 10

通过从文档中获取代码解决了这个问题

val options = listOf("Option 1", "Option 2", "Option 3", "Option 4", "Option 5")
var expanded by remember { mutableStateOf(false) }
var selectedOptionText by remember { mutableStateOf("") }
ExposedDropdownMenuBox(
    expanded = expanded,
    onExpandedChange = { expanded = !expanded },
) {
    TextField(
        // The `menuAnchor` modifier must be passed to the text field for correctness.
        modifier = Modifier.menuAnchor(),
        value = selectedOptionText,
        onValueChange = { selectedOptionText = it },
        label = { Text("Label") },
        trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
        colors = ExposedDropdownMenuDefaults.textFieldColors(),
    )
    // filter options based on text field value
    val filteringOptions = options.filter { it.contains(selectedOptionText, ignoreCase = true) }
    if (filteringOptions.isNotEmpty()) {
        ExposedDropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
        ) {
            filteringOptions.forEach { selectionOption ->
                DropdownMenuItem(
                    text = { Text(selectionOption) },
                    onClick = {
                        selectedOptionText = selectionOption
                        expanded = false
                    },
                    contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
                )
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我们将嵌套的 ExposedDropdownMenu 替换为

DropdownMenu(
    modifier = Modifier
        .background(Color.White)
        .exposedDropdownSize(true),
    properties = PopupProperties(focusable = false),
    expanded = expanded,
    onDismissRequest = { expanded = false },
)
Run Code Online (Sandbox Code Playgroud)

最终代码的外观和行为将符合预期。当您键入时,建议将动态跟随,并且用户输入不会被阻止

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun docs() {
    val options = listOf("Option 1", "comment", "Afghanistan", "Albania", "Algeria", "Andorra", "Egypt")
    var expanded by remember { mutableStateOf(false) }
    var selectedOptionText by remember { mutableStateOf("") }
    ExposedDropdownMenuBox(
        expanded = expanded,
        onExpandedChange = { expanded = !expanded },
    ) {
        TextField(
            // The `menuAnchor` modifier must be passed to the text field for correctness.
            modifier = Modifier.menuAnchor(),
            value = selectedOptionText,
            onValueChange = { selectedOptionText = it },
            label = { Text("Label") },
            trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
            colors = ExposedDropdownMenuDefaults.textFieldColors(
                focusedContainerColor = Color.White,
                unfocusedContainerColor = Color.White
            ),
        )
        // filter options based on text field value
        val filteringOptions = options.filter { it.contains(selectedOptionText, ignoreCase = true) }
        if (filteringOptions.isNotEmpty()) {
            DropdownMenu(
                modifier = Modifier
                    .background(Color.White)
                    .exposedDropdownSize(true)
                ,
                properties = PopupProperties(focusable = false),
                expanded = expanded,
                onDismissRequest = { expanded = false },
            ) {
                filteringOptions.forEach { selectionOption ->
                    DropdownMenuItem(
                        text = { Text(selectionOption) },
                        onClick = {
                            selectedOptionText = selectionOption
                            expanded = false
                        },
                        contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
                    )
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)