在 Jetpack Compose 中更改光标位置并强制使用 SingleLine of TextField
Change Cursor Position and force SingleLine of TextField in Jetpack Compose
找不到更改 TextField 的光标位置并使其成为单行的方法。有人找到办法了吗?
目前我使用的是最新的jetpack-compose 1.0.0-alpha03
版本。
要设置光标,您需要像这样设置 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 更新选择,否则用户无法移动光标或 type/delete。
对于 single-line,您需要在 TextField 可组合项上设置固定高度,并且您可能希望从用户输入中清除“\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)
}
}
找不到更改 TextField 的光标位置并使其成为单行的方法。有人找到办法了吗?
目前我使用的是最新的jetpack-compose 1.0.0-alpha03
版本。
要设置光标,您需要像这样设置 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 更新选择,否则用户无法移动光标或 type/delete。
对于 single-line,您需要在 TextField 可组合项上设置固定高度,并且您可能希望从用户输入中清除“\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)
}
}