Sang Woo
Sang Woo

Reputation: 1

Jetpack Compose TvLazyColumn PivotOffset for items with different sizes

I am using TvLazyColumn composable with 7 items, and inside of each item has a title and a TvLazyRow with a list of video thumbnail images which are focusable.

Out of the 7 items, 6 have identical header style (1 row header text) so the padding between the header and the TvLazyRow is identical. However, one item has a different header style (multiple-row header: LIVE badge, title row, information row).

When I scroll up and down the TvLazyColumn using D-pad, I want the top of each column item to be aligning with the top of TvLazyColumn, regardless of the focused thumnail image's vertical position. This means I want the column pivot to be set on the top of the title of each column items, and not on the thumbnail images.

If all 7 items have the identical 1 row text header style, I can simply adjust PivotOffset to achieve this. But I can't do so because the one item has different header style. Could someone please help me achieving this desired behavior?

From here:

enter image description here

If I press DOWN on my D-Pad

This is what I want:

enter image description here

But this is what I get instead - Notice the LIVE badge goes out of the bound:

enter image description here

Here is the code snippets:

            TvLazyColumn(
                modifier = Modifier
                    .fillMaxWidth()
                    .fillMaxHeight(0.5f)
                    .border(width = 2.dp, color = Color.Red)
                    .align(Alignment.BottomStart),
                pivotOffsets = PivotOffsets(parentFraction = 0.3f, childFraction = 0.2f),
                contentPadding = PaddingValues(bottom = 100.dp),
            ) {
                .
                .
                .

                if (homeViewState.userHistoryList.isNotEmpty()) {
                    item {
                        WTvMediaPostRow(
                            postList = homeViewState.userHistoryList,
                            title = stringResource(id = ...),
                            onPostClick = onItemClick,
                            onItemFocus = onItemFocus,
                        )
                    }
                }

                if (homeViewState.liveList.isNotEmpty()) {
                    item {
                        WTvLivePostRow(
                            postList = homeViewState.liveList,
                            title = stringResource(id = ...),
                            showLiveBadge = true,
                            onPostClick = onItemClick,
                            onItemFocus = onItemFocus,
                        )
                    }
                }

                .
                .
                .
            }

I tried setting different pivotOffsets value for the one item with different header style and it sort of works - the offset gets applied ONLY AFTER I start scrolling the TvLazyRow inside the column item. I want the offset to be applied as soon as the thumbnail gets focused.

enter image description here

            var currentFocusRowType by remember { mutableStateOf(WTvHomeRowType.EMPTY) }

            TvLazyColumn(
                modifier = Modifier
                    .fillMaxWidth()
                    .fillMaxHeight(0.5f)
                    .border(width = 2.dp, color = Color.Red)
                    .align(Alignment.BottomStart),
                pivotOffsets = if (currentFocusRowType == WTvHomeRowType.ON_LIVE) {
                    PivotOffsets(parentFraction = 0.5f, childFraction = 0.2f)
                } else {
                    PivotOffsets(parentFraction = 0.3f, childFraction = 0.2f)
                },
            ) {
                .
                .
                .

                if (homeViewState.liveList.isNotEmpty()) {
                    item {
                        WTvLivePostRow(
                            postList = homeViewState.liveList,
                            title = stringResource(id = ...),
                            showLiveBadge = true,
                            onPostClick = onItemClick,
                            onItemFocus = { index, post ->
                                currentFocusRowType = WTvHomeRowType.ON_LIVE
                                onItemFocus.invoke(index, post)
                            },
                        )
                    }
                }

                .
                .
                .
             }

I tried setting different pivotOffsets value for the one item with different header style and it sort of works - the offset gets applied ONLY AFTER I start scrolling the TvLazyRow inside the column item. I want the offset to be applied as soon as the thumbnail gets focused.

Upvotes: 0

Views: 1109

Answers (1)

Sang Woo
Sang Woo

Reputation: 1

In case anyone is facing the same issue, I was able to achieve the desired outcome by setting userScrollEnabled = false and use rememberTvLazyListState().scrollToItem() to manually scroll to each category when there's up & down D-pad input.

Here is the code snippet:

            val tvLazyListState = rememberTvLazyListState()
            val homeCategorySize = remember { mutableIntStateOf(7) }
            val currentIndex = remember { mutableIntStateOf(0) }

            TvLazyColumn(
                modifier = Modifier
                    .fillMaxWidth()
                    .fillMaxHeight(0.5f)
                    .align(Alignment.BottomStart)
                    .handleDPadKeyEvents(
                        onDown = {
                            coroutineScope.launch {
                                currentIndex.intValue = (++currentIndex.intValue).coerceIn(0, homeCategorySize.intValue - 1)
                                tvLazyListState.scrollToItem(currentIndex.intValue)
                            }
                            false
                        },
                        onUp = {
                            coroutineScope.launch {
                                currentIndex.intValue = (--currentIndex.intValue).coerceIn(0, homeCategorySize.intValue - 1)
                                tvLazyListState.scrollToItem(currentIndex.intValue)
                            }
                            false
                        },
                    ),
                state = tvLazyListState,
                userScrollEnabled = false,
                contentPadding = PaddingValues(bottom = 100.dp),
            ) {
               ...
            }

.handleDPadKeyEvents is an extension function I created using Modifier.onPreviewKeyEvents to handle certain key inputs differently.

The above method scrolls the TvLazyColumn to bring the view of the complete children as I wanted. Hope this helps to anyone facing similar issues.

Upvotes: 0

Related Questions