[SOLVED] Jetpack Compose: can’t change TextField focus


This Question and Answer are collected from stackoverflow and tested by JTuto community, is licensed under
CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

Issue

So, I have an AlertDialog with a ListItem inside, which in turn has 2 TextFields inside:

val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
val (nameFieldFocus, valueFieldFocus) = remember{FocusRequester.createRefs()}
AlertDialog(
    ...
    text = {
        ListItem(
            ...
            leadingContent = {
                Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
                    TextField(
                        modifier = Modifier.focusRequester(nameFieldFocus).focusProperties{next = valueFieldFocus}.focusable(),
                        value = someValue,
                        onValueChange = {someValue = it},
                        label = {Text(text = "Some label")},
                        keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
                        keyboardActions = KeyboardActions(onNext = {focusManager.moveFocus(FocusDirection.Next)}),
                        singleLine = true
                    )
                    TextField(
                        modifier = Modifier.focusRequester(valueFieldFocus).focusProperties{previous = nameFieldFocus}.focusable(),
                        value = anotherValue,
                        onValueChange = {anotherValue = it},
                        label = {Text(text = "Another label")},
                        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                        keyboardActions = KeyboardActions(onDone = {focusManager.clearFocus()}),
                        singleLine = true
                    )
                }
            }
        )
    }
)

The problem is, when I press the action key on the keyboard, no focus change occurs, regardless of whether the text fields have text in them or not. I also tried onNext = null and onDone = null, which is supposed to use the default implementation according to the documentation, but that also doesn’t behave as expected.

P.S. I’m using androidx.compose.material3.

Solution

You should call val focusManager = LocalFocusManager.current inside AlertDialog. Also, remove the Modifier.focusable().

AlertDialog(
    text = {

        val focusManager = LocalFocusManager.current

        val (nameFieldFocus, valueFieldFocus) = remember { FocusRequester.createRefs() }


        ListItem(
            leadingContent = {
                Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
                    TextField(
                        modifier = Modifier
                            .focusRequester(nameFieldFocus)
                            .focusProperties { next = valueFieldFocus },
                        value = someValue,
                        onValueChange = { someValue = it },
                        label = { Text(text = "Some label") },
                        keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
                        keyboardActions = KeyboardActions(onNext = {
                            focusManager.moveFocus(
                                FocusDirection.Next
                            )
                        }),
                        singleLine = true
                    )
                    TextField(
                        modifier = Modifier
                            .focusRequester(valueFieldFocus)
                            .focusProperties { previous = nameFieldFocus },
                        value = anotherValue,
                        onValueChange = { anotherValue = it },
                        label = { Text(text = "Another label") },
                        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                        keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
                        singleLine = true
                    )
                }
            },
            headlineText = {
                Text(text = "Headline Text")
            }
        )
    },
    confirmButton = {
        Button(onClick = { /*TODO*/ }) {
            Text(text = "Confirm")
        }
    },
    onDismissRequest = {

    }
)

Answered By – Thracian

people found this article helpful. What about you?