Couldn't find a way to change the cursor position of TextField and making it singleline. Someone find a way to do it?
At this time, I'm using the latest jetpack-compose 1.0.0-alpha03
version.
To set the cursor you need to set the selection of the TextFieldValue like this:
@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}
)
}
Keep in mind you need to update the selection yourself from the onValueChange otherwise the user cannot move the cursor or type/delete.
To the single-line, you need to set a fixed height on the TextField Composable and you probably want to sanitize '\n' from the user input.
@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
}
},
)
}
For the latter, I sanitize the new text and compare the lengths of it and the state's text, if the new text is shorter I do not have to update the state because I just removed the character during sanitizing. If you just want to stop the user from adding new lines on their own, you can leave the height unconstrained.
The previous solution ignores a pasted text with a line break, if you want to keep it this onValueChange implementation should handle it correctly:
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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With