在 Jetpack Compose 中选择 TextField 的所有文本

any*_*iek 3 textfield kotlin android-jetpack-compose

我在 Jetpack Compose 中使用 TextField 组件。获得焦点时如何选择所有文本?

Phi*_*hov 8

@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
            }
        }
)
Run Code Online (Sandbox Code Playgroud)

我认为应该可以让它变得更容易,所以我在 Compose 问题跟踪器上创建了这个问题


Tom*_*uis 6

我编写了一个修饰符扩展函数,尽管存在 @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
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

用法

@Composable
fun SelectAllOnFocusDemo() {
  var tfvState = remember {
    mutableStateOf(TextFieldValue("initial text"))
  }
  TextField(
    modifier = Modifier.onFocusSelectAll(tfvState),
    value = tfvState.value,
    onValueChange = { tfvState.value = it },
  )
}
Run Code Online (Sandbox Code Playgroud)


ngl*_*ber 5

在这种情况下,您应该使用TextFieldValueas 的状态TextField,当它获得焦点时,设置selectionusingTextFieldValue状态。

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)
                )
            }
        }
)
Run Code Online (Sandbox Code Playgroud)

结果如下:

在此处输入图片说明

请注意,根据您触摸的情况,光标会转到触摸的位置,而不是选择整个文本。您可以尝试弄清楚这是错误还是功能:)