簡體   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