更改光标位置并在Jetpack Compose中强制TextField的SingleLine行

时间:2020-09-25 13:13:16

标签: android kotlin textfield android-jetpack-compose

找不到改变TextField光标位置并使之成为单行的方法。有人找到一种方法吗?

目前,我正在使用最新的jetpack-compose 1.0.0-alpha03版本。

1 个答案:

答案 0 :(得分:3)

要设置光标,您需要像这样设置TextFieldValue的选择:

@Composable
fun Content() {
    val initTargetIndex = 3
    val initValue = "string"
    val initSelectionIndex = initTargetIndex.takeIf { it <= initValue.length } ?: initValue.length
    val textFieldValueState = remember {
        mutableStateOf(TextFieldValue(
            text = initValue,
            selection = TextRange(initSelectionIndex)
        ))
    }
    TextField(
        modifier = Modifier.height(50.dp),
        value = textFieldValueState.value,
        onValueChange = { tfv -> textFieldValueState.value = tfv}
    )
}

请记住,您需要自己通过onValueChange更新选择,否则用户将无法移动光标或键入/删除。

对于单行,您需要在TextField Composable上设置一个固定的高度,并且可能要清除用户输入中的'\ n'。

@Composable
fun Content() {
    val initTargetIndex = 3
    val initValue = "string"
    val initSelectionIndex = initTargetIndex.takeIf { it <= initValue.length } ?: initValue.length
    val textFieldValueState = remember {
        mutableStateOf(TextFieldValue(
            text = initValue,
            selection = TextRange(initSelectionIndex)
        ))
    }
    TextField(
        modifier = Modifier.height(50.dp),
        value = textFieldValueState.value,
        onValueChange = { tfv ->
            val sanitizedText = tfv.text.replace("\n", "")
            val needUpdate = sanitizedText.length >= tfv.text.length
            if (needUpdate) {
                textFieldValueState.value = tfv
            }
        },
    
    )
}

对于后者,我对新文本进行消毒,并将其长度与状态文本进行比较,如果新文本较短,则不必更新状态,因为在消毒过程中我只是删除了字符。 如果只想阻止用户自己添加新行,则可以使高度不受限制。

以前的解决方案会忽略带有换行符的粘贴文本,如果要保留它,此onValueChange实现应正确处理它:

val onValueChange = {tfv ->
    textFieldValueState.value.let { old ->
        val sanitizedText = tfv.text.replace("\n", "")
        val lastPositionIndex = sanitizedText.length
        val needUpdate = sanitizedText.length < tfv.text.length
        val selection = if (needUpdate) {
            tfv.selection.copy(
                start = old.selection.start.takeUnless { it > lastPositionIndex} ?: lastPositionIndex,
                end = old.selection.end.takeUnless { it > lastPositionIndex} ?: lastPositionIndex
            )
        } else tfv.selection
        val composition = old.composition?.let { oldComp ->
            if (needUpdate) {
               TextRange(
                    start = oldComp.start.takeUnless { it > lastPositionIndex} ?: lastPositionIndex,
                    end = oldComp.end.takeUnless { it > lastPositionIndex} ?: lastPositionIndex
                )
            } else oldComp
        }
        textFieldValueState.value = tfv.copy(text = sanitizedText, selection = selection, composition = composition)
    }
}