我正在尝试在现有的 AndroidTV 应用程序中使用 Jetpack Compose。 我需要制作一个带有麦克风图标的按钮,如果它聚焦,它的颜色就会改变。像这样^
注意力不集中
专注
这是我的 ComposeView
<androidx.compose.ui.platform.ComposeView
android:id="@+id/micBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
这是我片段中的代码
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,
)
}
}
看起来不错吧? 问题是,当我尝试关注此按钮时,焦点首先转到
AndroidComposeView
项目(根据我的 GlobalFocusListener
)。
只有我的第二个操作(单击、方向键导航)才能使我的内容集中。
所以,出于某种原因,内部
AndroidComposeView
从我的Content
中窃取了焦点
有什么办法可以防止这种行为吗?我只需要关注我的内容,而不是
AndroidComposeView
包装。
这是一个已知问题:
您可以创建一个扩展功能,可以将您的焦点转移给孩子。
@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()
}
}
}
用法非常简单。您现在可以使用
setContent
,而不是使用 setFocusableContent
。
binding.micBtn.setFocusableContent {
// ...
}
要对组件中的焦点变化做出反应,您可以使用 androidx.tv.material3
库中的
IconButton。默认情况下,当按钮聚焦时它会改变颜色,并且可以使用
colors
参数轻松更改不同状态(聚焦、按下等)的颜色。
用途:
androidx.tv.material3.IconButton(onClick = { }) {
Icon(
Icons.Filled.Mic,
contentDescription = "Mic"
)
}