6

由于某种原因 Compose TextField 的点击监听器对我不起作用。

@Composable
    private fun ExposedDropdown(
        modifier: Modifier,
        list: List<String>,
        priority: Int
    ) {
        var expanded by remember { mutableStateOf(false) }
        Column(modifier) {
            OutlinedTextField(
                value = list[priority],
                onValueChange = { },
                readOnly = true,
                singleLine = true,
                label = { Text(stringResource(id = R.string.status)) },
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable { Timber.i("Not working :(") }
                    .onFocusChanged { if (it.isFocused) expanded = !expanded },
                trailingIcon = {
                    Icon(
                        imageVector = Icons.Outlined.ArrowDropDown,
                        contentDescription = null,
                        modifier = Modifier
                            .clickable { expanded = !expanded }
                            .padding(16.dp)
                    )
                }
            )
            DropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false }
            ) {
                list.forEach { label ->
                    DropdownMenuItem(onClick = {
                        viewModel.setPriority(list.indexOf(label))
                        expanded = false
                    }) {
                        Text(text = label)
                    }
                }
            }
        }
    }

如您所见,我提出了不好的解决方案,onFocusChanged但效果不佳。

对于那些需要上下文的人,我正在尝试做 ExposedDropdown 但我希望它在我单击 TextField 上的任意位置时打开

4

5 回答 5

5

使用 compose 1.0.2它默认工作。需要加线enabled = false

例子

@Composable
fun SelectableTextField(
    modifier: Modifier = Modifier,
    textValue: String,
    onClick: () -> Unit
) {
    TextField(
        value = textValue,
        onValueChange = {},
        modifier = modifier
            .fillMaxWidth()
            .clickable { onClick() },
        enabled = false
    )
}

要消除涟漪效应,请使用此类扩展

inline fun Modifier.noRippleClickable(crossinline onClick: () -> Unit): Modifier =
    composed {
        clickable(indication = null,
            interactionSource = remember { MutableInteractionSource() }) {
            onClick()
        }
    }
于 2021-09-15T19:43:28.143 回答
2

另一种可能的解决方法是:

TextField(
    value = ...,
    onValueChange = { ... },
    interactionSource = remember { MutableInteractionSource() }
        .also { interactionSource ->
            LaunchedEffect(interactionSource) {
                interactionSource.interactions.collect {
                    if (it is PressInteraction.Release) {
                        // works like onClick
                    }
                }
            }
        }
)

于 2021-12-13T12:56:42.513 回答
2

当前的clickable修饰符 ( 1.0.0-beta08) 不适用于TextField.

这是一种解决方法,而不是真正的解决方案。
由于您TextField是只读的,因此您可以在一秒钟内将OutlinedTextFieldwith包装起来以处理点击。BoxBox

 val (focusRequester) = FocusRequester.createRefs()
 val interactionSource = remember { MutableInteractionSource() }

 Box() {
        OutlinedTextField(
          //...your code
          modifier = Modifier
            .fillMaxWidth()
            .focusRequester(focusRequester)
        }
                    
        if (!expanded) {
            Box(modifier = Modifier
                .matchParentSize()
                .clickable(
                    onClick = {
                        expanded = !expanded
                        focusRequester.requestFocus() //to give the focus to the TextField
                              },
                    interactionSource = interactionSource,
                    indication = null //to avoid the ripple on the Box
                ))
        }
    }
于 2021-06-09T12:20:13.503 回答
2

这是一个可能的解决方案。我创建了一个collectClickAsState()基于androidx.compose.foundation.interaction.collectIsPressedAsState

@Composable
fun CustomTextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    onClick: (() -> Unit)? = null,
) {
    val onClickSource = remember { MutableInteractionSource() }

    if (onClick != null) {
        if (onClickSource.collectClickAsState().value) {
            onClick.invoke()
        }
    }

    TextField(
        value = value,
        onValueChange = onValueChange,
        interactionSource = onClickSource,
        enabled = enabled,
        readOnly = onClick != null,
        modifier = modifier
            // add clickable to work with talkback/accessibility
            .clickable(enabled = enabled) { onClick?.invoke() },
    )
}

@Composable
fun InteractionSource.collectClickAsState(): State<Boolean> {
    val onClick = remember { mutableStateOf(false) }
    LaunchedEffect(this) {
        var wasPressed = false
        interactions.collect { interaction ->
            when (interaction) {
                is PressInteraction.Press -> {
                    wasPressed = true
                }
                is PressInteraction.Release -> {
                    if (wasPressed) onClick.value = true
                    wasPressed = false
                }
                is PressInteraction.Cancel -> {
                    wasPressed = false
                }
            }
            // reset state with some delay otherwise it can re-emit the previous state
            delay(10L)
            onClick.value = false
        }
    }
    return onClick
}

使用此解决方案,文本字段仍然是可聚焦的,文本是可选择的,并且它将使用正确的 UI 启用状态。

于 2021-11-12T22:52:14.367 回答
1

收听TextField点击动作的简单解决方案

val interactionSource = remember { MutableInteractionSource() }
val isPressed: Boolean by interactionSource.collectIsPressedAsState()

if (isPressed) {
    // Click action
}

TextField(
    value = textFieldValue,
    onValueChange = onTextFieldChange,
    interactionSource = interactionSource
)
于 2022-01-06T04:03:39.697 回答