Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jetpack compose RequestFocus works only once

I'm building a scenario where a button click generates a new screen title and content. Per the accessibility requirements, a button click should place a TalkBack focus on the screen title, so the user could hear what the new content is about.

The screen should be something like this:

Column(){
    Title()
    Content()
    RefreshContentButton()
}

I use a FocusRequester instance to request focus when the button is clicked. This works well for the first time, when the user traverses back to the refresh button and clicks on it, the focus won't change.

I've set up an example that shows the issue. With TalkBack enabled, the first button click successfully puts a focus on the respective Focusable, the second click doesn't do anything. However, if I alternate button clicks, then everything works just fine.

class MainActivity : ComponentActivity() {
    @OptIn(ExperimentalComposeUiApi::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val (ref1, ref2) = remember { FocusRequester.createRefs() }
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.SpaceBetween,
            ) {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceAround
                ) {
                    Focusable("Focusable #1", ref1)
                    Focusable("Focusable #2", ref2)
                }
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceAround
                ) {
                    Button(
                        onClick = {
                            ref1.requestFocus()
                        }) {
                        Text(text = "Focus on #1")
                    }
                    Button(
                        onClick = {
                            ref2.requestFocus()
                        }) {
                        Text(text = "Focus on #2")
                    }
                }
            }
        }
    }
}

@Composable
fun Focusable(text: String, focusRequester: FocusRequester) {
    Box(
        modifier = Modifier.height(100.dp),
        contentAlignment = Alignment.Center,
    ) {
        Text(text = text, modifier = Modifier
            .focusRequester(focusRequester)
            .focusable(true)
            .focusProperties {
                canFocus = true
            }
            .focusTarget())
    }
}
like image 274
metz82 Avatar asked Sep 03 '25 06:09

metz82


1 Answers

Try adding:

val focusManager = LocalFocusManager.current

And then for the buttons:

  onClick = {
     focusManager.clearFocus(true)
     yourRef.requestFocus()
 }
like image 122
Matt Grier Avatar answered Sep 04 '25 20:09

Matt Grier