Jetpack Compose 是否提供 Material AutoComplete TextView 替代品?

mac*_*our 11 android material-components-android android-jetpack-compose

在将我的应用程序迁移到 Jetpack compose 的过程中,我遇到了应用程序中 TextField 需要自动完成功能的部分。

但是,从版本 1.0.0-alpha05 开始,我找不到任何使用 Compose API 实现此目的的功能。我发现的最接近的东西是DropdownMenuDropdownMenuItem可组合项,但似乎需要大量手动管道才能从中创建自动完成菜单。

当然,显而易见的事情就是等待 Jetpack Compose 的未来更新。但我想知道,在迁移中遇到此问题的人是否找到了解决方案?

小智 10

至少在 v1.0.2 之前没有

所以我在这个要点中实现了一个很好的工作组合

我也把它放在这里:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.window.PopupProperties


@Composable
fun TextFieldWithDropdown(
    modifier: Modifier = Modifier,
    value: TextFieldValue,
    setValue: (TextFieldValue) -> Unit,
    onDismissRequest: () -> Unit,
    dropDownExpanded: Boolean,
    list: List<String>,
    label: String = ""
) {
    Box(modifier) {
        TextField(
            modifier = Modifier
                .fillMaxWidth()
                .onFocusChanged { focusState ->
                    if (!focusState.isFocused)
                        onDismissRequest()
                },
            value = value,
            onValueChange = setValue,
            label = { Text(label) },
            colors = TextFieldDefaults.outlinedTextFieldColors()
        )
        DropdownMenu(
            expanded = dropDownExpanded,
            properties = PopupProperties(
                focusable = false,
                dismissOnBackPress = true,
                dismissOnClickOutside = true
            ),
            onDismissRequest = onDismissRequest
        ) {
            list.forEach { text ->
                DropdownMenuItem(onClick = {
                    setValue(
                        TextFieldValue(
                            text,
                            TextRange(text.length)
                        )
                    )
                }) {
                    Text(text = text)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如何使用它

val all = listOf("aaa", "baa", "aab", "abb", "bab")

val dropDownOptions = mutableStateOf(listOf<String>())
val textFieldValue = mutableStateOf(TextFieldValue())
val dropDownExpanded = mutableStateOf(false)
fun onDropdownDismissRequest() {
    dropDownExpanded.value = false
}

fun onValueChanged(value: TextFieldValue) {
    dropDownExpanded.value = true
    textFieldValue.value = value
    dropDownOptions.value = all.filter { it.startsWith(value.text) && it != value.text }.take(3)
}

@Composable
fun TextFieldWithDropdownUsage() {
    TextFieldWithDropdown(
        modifier = Modifier.fillMaxWidth(),
        value = textFieldValue.value,
        setValue = ::onValueChanged,
        onDismissRequest = ::onDropdownDismissRequest,
        dropDownExpanded = dropDownExpanded.value,
        list = dropDownOptions.value,
        label = "Label"
    )
Run Code Online (Sandbox Code Playgroud)


mac*_*our 9

从 compose 1.1.0-alpha06 开始,Compose Material 现在提供了一个ExposedDropdownMenu组合的 API ,可用于实现下拉菜单,从而促进自动完成过程。实际的自动完成逻辑必须自己实现。

API 文档给出了以下可编辑字段的用法示例:

val options = listOf("Option 1", "Option 2", "Option 3", "Option 4", "Option 5")
var exp by remember { mutableStateOf(false) }
var selectedOption by remember { mutableStateOf("") }
ExposedDropdownMenuBox(expanded = exp, onExpandedChange = { exp = !exp }) {
    TextField(
        value = selectedOption,
        onValueChange = { selectedOption = it },
        label = { Text("Label") },
        trailingIcon = {
            ExposedDropdownMenuDefaults.TrailingIcon(expanded = exp)
        },
        colors = ExposedDropdownMenuDefaults.textFieldColors()
    )
    // filter options based on text field value (i.e. crude autocomplete)
    val filterOpts = options.filter { it.contains(selectedOption, ignoreCase = true) }
    if (filterOpts.isNotEmpty()) {
        ExposedDropdownMenu(expanded = exp, onDismissRequest = { exp = false }) {
            filterOpts.forEach { option ->
                DropdownMenuItem(
                    onClick = {
                        selectedOption = option
                        exp = false
                    }
                ) {
                    Text(text = option)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您提供示例链接。唯一不起作用的是过滤。弹出菜单总是奇怪地消失。还有谁? (2认同)