Search code examples
android-jetpack-composeandroid-jetpack-compose-textandroid-jetpack-compose-list

ImeAction moves cursor to the beginning of a TextField


When i click "Next" ImeAction, the cursor position goes to a previous remembered position (i.e. if you ever manually set a cursor position) for newly selected TextField. If there was none, then the cursor jumps to the start, even though the TextField is not empty. I expected the cursor always be in the end, when focus was gained via ImeAction.

Sample code (for simplicity i hold mutable states right here, not using ViewModel):

@Composable
fun ImeActionIsBroken() {
    val focusRequester = remember { FocusRequester() }
    Column {
        var value1 by rememberSaveable { mutableStateOf("Some value 1") }
        TextField(
            value = value1,
            onValueChange = { value1 = it },
            modifier = Modifier.fillMaxWidth(),
            keyboardActions = KeyboardActions {
                focusRequester.requestFocus()
            },
            singleLine = true
        )

        var value2 by rememberSaveable { mutableStateOf("Some value 2") }
        TextField(
            value = value2,
            onValueChange = { value2 = it },
            modifier = Modifier
                .fillMaxWidth()
                .focusRequester(focusRequester),
            singleLine = true
        )
    }
}

Compose version 1.0.5


Solution

  • You can use the TextFieldValue object instead of using String for our TextField. With that, you can customize the selected range of text / or where the text cursor should be.

    In your example, you should move up the declaration of the value2 to be accessible by the KeyboardAction callback of the first text field. Then update it to be a TextFieldValue, like so :

    var value2 by rememberSaveable { mutableStateOf(TextFieldValue("Some value 2")) }
    

    And inside the KeyboardAction you can just update the selection to be at the end of the field, before requesting the focus, like that :

    value2 = value2.copy(selection = TextRange(value2.text.length))
    focusRequester.requestFocus()