简体   繁体   English

选择 Jetpack Compose 中 TextField 的所有文本

[英]Select all text of TextField in Jetpack Compose

I'm using TextField component in Jetpack Compose.我在 Jetpack Compose 中使用 TextField 组件。 How to select all text when it receive focus?获得焦点时如何选择所有文本?

In this case you should use TextFieldValue as state of your TextField , and when it receive focus, you set the selection using the TextFieldValue state.在这种情况下,您应该使用TextFieldValue作为TextField的状态,当它获得焦点时,您使用TextFieldValue状态设置selection

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

Here's the result:结果如下:

在此处输入图像描述

Notice that depending on you're touching the cursor goes to the touched position instead of select the entire text.请注意,根据您的触摸,光标会转到触摸的位置,而不是选择整个文本。 You can try to figure it out if this is a bug or a feature :)您可以尝试弄清楚这是错误还是功能:)

@nglauber solution doesn't seems to work anymore. @nglauber 解决方案似乎不再起作用。

Debugging shows that onFocusChanged is called before onValueChange and within one view life cycle.调试显示onFocusChangedonValueChange之前被调用,并且在一个视图生命周期内。 A selection changed during onFocusChanged has no effect on TextField , since it is overridden during onValueChange .onFocusChanged期间更改的选择对TextField没有影响,因为它在onValueChange期间被覆盖。

Here's a possible workaround:这是一个可能的解决方法:

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

I think it should be possible to make it easier, so I created this question on Compose issue tracker.我认为应该可以让它变得更容易,所以我在 Compose 问题跟踪器上创建了这个问题

I didn't have 100% success with @nglauber answer. @nglauber 的回答并没有 100% 成功。 You should add a small delay and it works great.您应该添加一个小的延迟,并且效果很好。 For example:例如:

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

I wrote a Modifier extension function that works in spite of bug pointed out by @Pylyp尽管@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))
      }
    }
    Modifier.onFocusChanged { focusState ->
      if (focusState.isFocused) {
        triggerEffect = triggerEffect?.let { bool ->
          !bool
        } ?: true
      }
    }
  }

usage用法

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM