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

问题描述 投票:0回答:5

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

kotlin textfield android-jetpack-compose
5个回答
18
投票

在这种情况下,您应该使用

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)
                )
            }
        }
)

结果如下:

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


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
            }
        }
)

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


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
      }
    }
  }

用法

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

3
投票

@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)
                            )
                        }
                    }
                }
        )

2
投票

我想添加到菲尔的答案我想动态更新状态,我最终得到了这个:

var state by remember(textVal) {
    mutableStateOf(TextFieldValue(text = textVal, selection = TextRange(textVal.length)))
}

它做了两件事,首先,如果您的

textVal
发生变化,它会更新字段,还将光标放在末尾。

© www.soinside.com 2019 - 2024. All rights reserved.