I'm trying to use Jetpack Compose in my existing AndroidTV App. I need to make a button with microphone icon which will change its color if it's focused. Like this^
Unfocused
Focused
Here's my ComposeView
<androidx.compose.ui.platform.ComposeView
android:id="@+id/micBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
And here the code in my fragment
binding.micBtn.setContent {
var buttonResId by remember { mutableStateOf(R.drawable.speech_recognition_button_unfocused) }
IconButton(
modifier = Modifier
.size(60.dp)
.onFocusChanged {
buttonResId = if (it.isFocused) {
R.drawable.speech_recognition_button_focused
} else {
R.drawable.speech_recognition_button_unfocused
}
},
onClick = onClick,
) {
Icon(
painter = painterResource(id = buttonResId),
contentDescription = null,
tint = Color.Unspecified,
)
}
}
Looks good, right?
The problem is when I try to focus on this button focus first goes to AndroidComposeView item (according to my GlobalFocusListener).
And only my second action (click, D-Pad navigation) makes my content focused.
So, for some reason internal AndroidComposeView steals focus from my Content
Is there any way to prevent this behaviour? I need to focus only on my content, not AndroidComposeView wrapper.


Update (March 6, 2024):
This issue has been addressed in aosp/2813125 and the following hack shouldn't be required anymore. Just update to the latest version of Compose UI (1.7.x).
First draft
This is a known issue where moving focus from outside of a ComposeView to inside the ComposeView needs 2 inputs from the user instead of just 1: b/292432034
You can create an extension function which can transfer the focus to the child using just 1 input from the user.
Usage is pretty straight forward. Instead of using
setContent, you can now usesetFocusableContent.Unrelated to the question
To react to focus changes in your component, you can make use of IconButton from
androidx.tv.material3library. By default, it changes color when the button is focused and it is easy to change the colors for different states (focused, pressed, etc.) using thecolorsparameter.Usage: