Change Cursor Position And Force Singleline Of Textfield In Jetpack Compose
Solution 1:
To set the cursor you need to set the selection of the TextFieldValue like this:
@ComposablefunContent() {
val initTargetIndex = 3val 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.
@ComposablefunContent() {
val initTargetIndex = 3val 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)
}
}
Post a Comment for "Change Cursor Position And Force Singleline Of Textfield In Jetpack Compose"