如何实现TvLazyRow标题与项目枢轴偏移量精准匹配?
解决TvLazyRow标题与高亮项起始对齐的问题
要实现类似PrimeVideo的标题与高亮项左对齐效果,不能依赖固定内边距(适配性差),核心思路是动态监听焦点项位置,让列表滚动时自动将高亮项左边缘与标题左边缘对齐,以下是具体实现方案:
方案1:利用TvLazyListState动态滚动对齐
通过监听焦点项的索引变化,自动滚动列表使高亮项的左边缘与列表左边界对齐,同时让标题和列表使用相同的左内边距,即可实现标题与高亮项的起始对齐:
@Composable fun AlignedTvRow(title: String, itemList: List<YourItemType>) { val lazyListState = rememberTvLazyListState() val paddingStart = 16.dp // 标题和列表统一的左内边距 // 焦点切换时自动滚动对齐 LaunchedEffect(lazyListState.focusedItemIndex) { val targetIndex = lazyListState.focusedItemIndex if (targetIndex != -1) { // 获取当前焦点项相对于列表起始位置的偏移量 val itemOffset = lazyListState.layoutInfo.visibleItemsInfo .find { it.index == targetIndex } ?.offset ?: 0 // 滚动到目标项,抵消偏移量使其左边缘与列表左边界对齐 lazyListState.animateScrollToItem( index = targetIndex, scrollOffset = -itemOffset ) } } Column(modifier = Modifier.fillMaxWidth()) { // 标题使用统一的左内边距 Text( text = title, modifier = Modifier.padding(start = paddingStart, bottom = 8.dp), style = MaterialTheme.typography.headlineSmall ) TvLazyRow( state = lazyListState, contentPadding = PaddingValues(start = paddingStart, end = paddingStart) ) { items(itemList) { item -> // 你的列表项布局,比如卡片 YourItemCard(item = item) } } } }
方案2:动态调整标题偏移(备选)
如果需要保持列表原有滚动逻辑,也可以通过监听焦点项的偏移量,动态调整标题的X轴偏移,使其始终与高亮项左边缘对齐:
@Composable fun OffsetAlignedTvRow(title: String, itemList: List<YourItemType>) { val lazyListState = rememberTvLazyListState() val titleOffsetX = remember { mutableStateOf(0.dp) } val listPaddingStart = 16.dp LaunchedEffect(lazyListState.focusedItemIndex) { lazyListState.layoutInfo.visibleItemsInfo .find { it.index == lazyListState.focusedItemIndex } ?.let { itemInfo -> // 计算标题需要偏移的距离,抵消焦点项的滚动偏移 titleOffsetX.value = (-itemInfo.offset).dp } } Column(modifier = Modifier.fillMaxWidth()) { Text( text = title, modifier = Modifier .padding(start = listPaddingStart, bottom = 8.dp) .offset(x = titleOffsetX.value), style = MaterialTheme.typography.headlineSmall ) TvLazyRow( state = lazyListState, contentPadding = PaddingValues(start = listPaddingStart, end = listPaddingStart) ) { items(itemList) { item -> YourItemCard(item = item) } } } }
关键说明
- 两种方案均基于
TvLazyListState的焦点状态动态计算,完全适配不同屏幕尺寸、不同item宽度的场景,避免了固定内边距的适配问题。 - 方案1是更贴近PrimeVideo的实现逻辑,通过列表滚动让高亮项对齐标题;方案2适合需要保留列表自由滚动的场景,通过标题偏移实现对齐。
内容的提问来源于stack exchange,提问作者Bharat Kumar
相关产品推荐
相关产品推荐

