我正在尝试使用 Compose 在 Android TV 上实现轮播组件,但我在使用方向键快速滚动时遇到了问题。注意:我想将焦点项目保留为屏幕上第一个显示的项目。
这里是屏幕截图:
通过在每个项目之后按下并释放右键来滚动前 5 个项目。接下来的 15 个项目通过按住右键滚动到列表的末尾。
滚动和焦点管理效果很好,但我想让它更快。在屏幕截图上,您会看到当按下右键时,列表会滚动 然后 下一个项目获得焦点。真的很慢
这是可组合函数:
@Composable
private fun CustomLazyRow() {
val scrollState = rememberLazyListState()
LazyRow(
state = scrollState,
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
itemsIndexed(
items = (1..20).toList()
) { index, item ->
var isFocused by remember { mutableStateOf(false) }
Text(
text = "Item $item",
modifier = Modifier
.dpadNavigation(scrollState, index)
.width(156.dp)
.aspectRatio(4 / 3F)
.onFocusChanged { isFocused = it.isFocused }
.focusable()
.border(if (isFocused) 4.dp else Dp.Hairline, Color.Black)
)
}
}
}
和
dpadNavigation
修饰符函数:
fun Modifier.dpadNavigation(
scrollState: LazyListState,
index: Int
) = composed {
val focusManager = LocalFocusManager.current
var focusDirectionToMove by remember { mutableStateOf<FocusDirection?>(null) }
val scope = rememberCoroutineScope()
onKeyEvent {
if (it.type == KeyEventType.KeyDown) {
when (it.nativeKeyEvent.keyCode) {
KeyEvent.KEYCODE_DPAD_LEFT -> focusDirectionToMove = FocusDirection.Left
KeyEvent.KEYCODE_DPAD_RIGHT -> focusDirectionToMove = FocusDirection.Right
}
if (focusDirectionToMove != null) {
scope.launch {
if (focusDirectionToMove == FocusDirection.Left && index > 0) {
// This does not work:
// scope.launch { scrollState.animateScrollToItem(index - 1) }
scrollState.animateScrollToItem(index - 1)
focusManager.moveFocus(FocusDirection.Left)
}
if (focusDirectionToMove == FocusDirection.Right) {
// scope.launch { scrollState.animateScrollToItem(index + 1) }
scrollState.animateScrollToItem(index + 1)
focusManager.moveFocus(FocusDirection.Right)
}
}
}
}
true
}
}
我以为是
animateScrollToItem
函数在执行moveFocus
之前必须完成。
所以我尝试在它自己的
animateScrollToItem
块中执行launch
但是它没有用;在这种情况下根本没有滚动。
您可以在 https://github.com/geekarist/perf-carousel 的 repo 中查看完整的源代码
Google 正在努力使 Jetpack compose 与电视兼容。结帐Android TV Compose 发布.
要回答您的问题,您可以使用 TvLazyRow 可组合项来构建与电视兼容的惰性行。为了保持焦点在同一位置,您可以使用
pivotOffset
(PivotOffset) param TvLazyRow 将行内的项目定位在固定位置。