ComposeView 抢走了 AndroidTV 内容的焦点

Nik*_*gin 3 android android-tv android-jetpack-compose android-jetpack-compose-tv

我正在尝试在现有的 AndroidTV 应用程序中使用 Jetpack Compose。我需要制作一个带有麦克风图标的按钮,如果它聚焦,它的颜色就会改变。像这样^

不专心

在此输入图像描述

专注

在此输入图像描述

这是我的 ComposeView

<androidx.compose.ui.platform.ComposeView
    android:id="@+id/micBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
Run Code Online (Sandbox Code Playgroud)

这是我的片段中的代码

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,
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来不错,对吧?问题是,当我尝试关注此按钮时,焦点首先转到AndroidComposeView项目(根据我的GlobalFocusListener)。只有我的第二个操作(单击、方向键导航)才能使我的内容集中。

所以,出于某种原因,内部AndroidComposeView窃取了我的注意力Content

有什么办法可以防止这种行为吗?我只需要关注我的内容,而不是AndroidComposeView包装。

Vig*_*aut 5

这是一个已知问题,将焦点从 ComposeView 外部移动到 ComposeView 内部需要用户输入 2 个输入,而不是 1 个:b/292432034

您可以创建一个扩展函数,只需用户的 1 个输入即可将焦点转移到子级。

@OptIn(ExperimentalFoundationApi::class)
fun ComposeView.setFocusableContent(content: @Composable () -> Unit) {
    isFocusable = true
    isFocusableInTouchMode = true
    val focusRequester = FocusRequester()

    onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
        if (hasFocus) focusRequester.requestFocus()
    }

    setContent {
        Box(modifier = Modifier.focusRequester(focusRequester).focusGroup()) {
            content.invoke()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法非常简单。setContent您现在可以使用 ,而不是使用setFocusableContent

binding.micBtn.setFocusableContent {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

与问题无关

要对组件中的焦点变化做出反应,您可以使用库中的IconButtonandroidx.tv.material3。默认情况下,当按钮聚焦时它会改变颜色,并且可以使用参数轻松更改不同状态(聚焦、按下等)的颜色colors

用法:

androidx.tv.material3.IconButton(onClick = { }) {
    Icon(
        Icons.Filled.Mic, 
        contentDescription = "Mic"
    )
}
Run Code Online (Sandbox Code Playgroud)