Jetpack Compose中如何选择TextField的所有文本

21

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

5个回答

16
在这种情况下,您应该使用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)
                )
            }
        }
)

这是结果:

在此输入图像描述

请注意,根据您的触摸位置,光标会移动到触摸位置而不是选择整个文本。您可以尝试确定这是否是一个错误还是一项功能 :)


7
@nglauber的解决方案似乎不再起作用。
调试结果显示,在一个视图生命周期内,在onValueChange之前会调用onFocusChanged。因此在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问题跟踪器上创建了这个问题


5

我写了一个修饰符扩展函数,尽管@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
      }
    }
  }

使用方法

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

2

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

1
我也遇到了这个问题,它不能一直正常工作。我正在使用imePadding,我想知道是否会影响它的工作。我加入了100毫秒的延迟,问题得到了解决。 - Blake

1

我想要补充一下Phil的回答,我想要动态更新状态,最终得到了这个:

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

它有两个作用,首先如果您的textVal更改,则更新字段,同时将光标放在末尾。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接