繁体   English   中英

Jetpack Compose:可单击的 TextField 不起作用

[英]Jetpack Compose: TextField clickable does not work

出于某种原因,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 上的任意位置时打开

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

这是一种解决方法,而不是真正的解决方案。
由于您的TextField是只读的,因此您可以使用第二个BoxOutlinedTextField包装在一个Box中以处理单击。

 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
                ))
        }
    }

将 enabled 属性设置为 false 的建议有效,但这会影响样式。 如果您希望它在视觉上与启用的 TextField 匹配,则相应地设置 colors 属性:

OutlinedTextField(
   value = "Example",
   enabled = false,
   onValueChange = {},
   modifier = Modifier.clickable { doSomeBehavior() },
   colors = TextFieldDefaults.outlinedTextFieldColors(
      disabledTextColor = MaterialTheme.colorScheme.onSurface,
      disabledBorderColor = MaterialTheme.colorScheme.outline,
      disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant,
      disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
      //For Icons
      disabledLeadingIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
      disabledTrailingIconColor = MaterialTheme.colorScheme.onSurfaceVariant)
)

使用 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()
        }
    }

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

@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 的 state。

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

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

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

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

if (isPressed) {
    // Click action
}

TextField(
    value = textFieldValue,
    onValueChange = onTextFieldChange,
    interactionSource = interactionSource
)
TextField(
        modifier = Modifier
            .fillMaxWidth()
            .**clickable**(onClick = onClick),
        enabled = false,
        value = currentSelection,
        onValueChange = { },
        label = {
            
        }
    )

使用 enabled = false 和 clickable 修饰符。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM