我正在 Jetpack Compose 中使用 TextField 组件。 如何在获得焦点时选择所有文本?
在这种情况下,您应该使用
TextFieldValue
作为 TextField
的状态,当它获得焦点时,您可以使用 selection
状态设置 TextFieldValue
。
val state = remember {
mutableStateOf(TextFieldValue(""))
}
TextField(
value = state.value,
onValueChange = { text -> state.value = text },
modifier = Modifier
.onFocusChanged { focusState ->
if (focusState.isFocused) {
val text = state.value.text
state.value = state.value.copy(
selection = TextRange(0, text.length)
)
}
}
)
结果如下:
请注意,根据您的触摸情况,光标会转到触摸的位置,而不是选择整个文本。您可以尝试弄清楚这是一个错误还是一个功能:)
@nglauber 解决方案似乎不再有效。
调试显示,
onFocusChanged
在onValueChange
之前调用,且在一个视图生命周期内。在 onFocusChanged
期间更改的选择对 TextField
没有影响,因为它在 onValueChange
期间被覆盖。
这是一个可能的解决方法:
var state by remember {
mutableStateOf(TextFieldValue("1231"))
}
var keepWholeSelection by remember { mutableStateOf(false) }
if (keepWholeSelection) {
// in case onValueChange was not called immediately after onFocusChanged
// the selection will be transferred correctly, so we don't need to redefine it anymore
SideEffect {
keepWholeSelection = false
}
}
TextField(
value = state,
onValueChange = { newState ->
if (keepWholeSelection) {
keepWholeSelection = false
state = newState.copy(
selection = TextRange(0, newState.text.length)
)
} else {
state = newState
}
},
modifier = Modifier
.onFocusChanged { focusState ->
if (focusState.isFocused) {
val text = state.text
state = state.copy(
selection = TextRange(0, text.length)
)
keepWholeSelection = true
}
}
)
我认为应该可以让它变得更容易,所以我在 Compose 问题跟踪器上创建了这个问题。
我编写了一个修饰符扩展函数,尽管@Pylyp指出了错误,但它仍然可以工作
fun Modifier.onFocusSelectAll(textFieldValueState: MutableState<TextFieldValue>): Modifier =
composed(
inspectorInfo = debugInspectorInfo {
name = "textFieldValueState"
properties["textFieldValueState"] = textFieldValueState
}
) {
var triggerEffect by remember {
mutableStateOf<Boolean?>(null)
}
if (triggerEffect != null) {
LaunchedEffect(triggerEffect) {
val tfv = textFieldValueState.value
textFieldValueState.value = tfv.copy(selection = TextRange(0, tfv.text.length))
}
}
onFocusChanged { focusState ->
if (focusState.isFocused) {
triggerEffect = triggerEffect?.let { bool ->
!bool
} ?: true
}
}
}
用法
@Composable
fun SelectAllOnFocusDemo() {
var tfvState = remember {
mutableStateOf(TextFieldValue("initial text"))
}
TextField(
modifier = Modifier.onFocusSelectAll(tfvState),
value = tfvState.value,
onValueChange = { tfvState.value = it },
)
}
@nglauber 的回答并没有 100% 成功。您应该添加一点延迟,效果很好。例如:
val state = remember {
mutableStateOf(TextFieldValue(""))
}
// get coroutine scope from composable
val scope = rememberCoroutineScope()
TextField(
value = state.value,
onValueChange = { text -> state.value = text },
modifier = Modifier
.onFocusChanged {
if (it.hasFocus) {
// start coroutine
scope.launch {
// add your preferred delay
delay(10)
val text = state.value.text
state.value = state.value.copy(
selection = TextRange(0, text.length)
)
}
}
}
)
我想添加到菲尔的答案我想动态更新状态,我最终得到了这个:
var state by remember(textVal) {
mutableStateOf(TextFieldValue(text = textVal, selection = TextRange(textVal.length)))
}
它做了两件事,首先,如果您的
textVal
发生变化,它会更新字段,还将光标放在末尾。