Jetpack Compose – 修改滚动行为以保持焦点在屏幕上的固定位置

huangapple go评论77阅读模式
英文:

Jetpack Compose - Modify scroll behavior to hold focus on a fix position on screen

问题

使用Jetpack Compose创建一个面向电视平台的应用程序,我一直在尝试在Jetpack Compose中创建一个在屏幕上固定位置并能滚动的行,以下是在Google TV启动器上观察到的目标行为:

目标行为

在这里,我们可以看到视图固定在屏幕的左侧,而整个行在其周围移动。

而下面是我的lazyrow组合的当前行为:

当前行为

正如我们在这里所看到的,焦点在列表开始围绕其移动之前会一直移动到右侧或左侧。

是否有帮助使lazyrow的滚动行为像第一个示例中的那样?

英文:

Using jetpack compose to create an AP for TV platforms and I've been trying to create a row in jetpack compose which scrolls about the fix position on screen, here is the target behaviour as observed on google TV launcher:

Target Behaviour

Here we can see that the view is fixed on the lefthand side of the screen while the entire row moves around it

And how here is the current behaviour with my lazyrow composable:

Current Behaviour

As we can see here, the focus moves all the way to the right or the left before the list starts moving around it.

Any help in making the lazyrow scroll behave like in the first example?

答案1

得分: 4

你可以使用Compose for TV库中的TvLazyRow来解决这个问题。它是androidx.tv.foundation.lazy.list包的一部分。

要使用它,你可以使用接受PivotOffsets类实例的pivotOffsets参数。你可以传递两个参数:

  • parentFraction 定义了子元素的起始边缘相对于父元素的起始边缘的偏移量
  • childFraction 定义了子元素的起始边缘相对于由parentFraction定义的枢轴的偏移量

以下是将项目放置在中心的示例用法:

import androidx.tv.foundation.lazy.list.TvLazyRow

TvLazyRow(
    pivotOffsets = PivotOffsets(0.5f, 0.5f),
    horizontalArrangement = Arrangement.spacedBy(20.dp)
) {
    items(10) {
        Card(backgroundColor = Color.Red)
    }
}

如果你想要类似Google TV启动器的外观,你可以将PivotOffsets更新为以下内容:

import androidx.tv.foundation.lazy.list.TvLazyRow

TvLazyRow(
    pivotOffsets = PivotOffsets(0.1f, 0f),
    horizontalArrangement = Arrangement.spacedBy(20.dp)
) {
    items(10) {
        Card(backgroundColor = Color.Red)
    }
}
英文:

You can make use of TvLazyRow from the Compose for TV library which solves exactly this problem. It is part of the androidx.tv.foundation.lazy.list package.

To use it, you can make use of the pivotOffsets argument which accepts a PivotOffsets class instance. To that, you can pass 2 arguments:

  • parentFraction which defines the offset of the starting edge of the child element from the starting edge of the parent element
  • childFraction defines the offset of the starting edge of the child from the pivot defined by parentFraction

Following is the sample usage which places the item exactly at the center:

Jetpack Compose – 修改滚动行为以保持焦点在屏幕上的固定位置

import androidx.tv.foundation.lazy.list.TvLazyRow

TvLazyRow(
    pivotOffsets = PivotOffsets(0.5f, 0.5f),
    horizontalArrangement = Arrangement.spacedBy(20.dp)
) {
    items(10) {
        Card(backgroundColor = Color.Red)
    }
}

If you want the Google TV launcher like look, you can update the PivotOffsets to the following:

Jetpack Compose – 修改滚动行为以保持焦点在屏幕上的固定位置

import androidx.tv.foundation.lazy.list.TvLazyRow

TvLazyRow(
    pivotOffsets = PivotOffsets(0.1f, 0f),
    horizontalArrangement = Arrangement.spacedBy(20.dp)
) {
    items(10) {
        Card(backgroundColor = Color.Red)
    }
}

答案2

得分: 1

// 我实际上只是计算第一个可见项的偏移是否超出视口的边界,如果是的话,就将惰性列表滚动到该项。
英文:

We can use the snap fling behavior that would snap at the middle item but the video you provided has snapping enabled on the first visible item, there's no property of snap fling that we could change to snap at the first item.

So I have implemented something that calculates and stop at the very first item and highlights it.

I did not see that you were implementing it for tv and I created a sample for mobile :___( .
If there is any tv specific api available for this behavior you should surely go for that, if not then you can have a look at my implementation.

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MainScreen(
    modifier: Modifier
) {
    
    val lazyRowState = rememberLazyListState()
    val snappingLayout = remember(lazyRowState) { SnapLayoutInfoProvider(lazyRowState) }
    val flingBehavior = rememberSnapFlingBehavior(snappingLayout)

    Box(
        modifier = modifier
        .fillMaxSize()
    ) {
        val firstVisibleItem by remember {
            derivedStateOf {
                lazyRowState.layoutInfo.visibleItemsInfo.firstOrNull()
            }
        }
        val viewPortStartOffset by remember {
            derivedStateOf {
                lazyRowState.layoutInfo.viewportStartOffset
            }
        }
        LaunchedEffect(key1 = firstVisibleItem ) {
            firstVisibleItem?.let {
                if(it.offset < viewPortStartOffset){
                    lazyRowState.animateScrollToItem(it.index)

                }
            }
        }
        LazyRow(
            modifier = Modifier
                .align(Alignment.Center)
                .wrapContentSize(),
            state = lazyRowState,
            flingBehavior = flingBehavior
        ) {

            items(50) { index ->
                val isFirstItem by remember { derivedStateOf { lazyRowState.firstVisibleItemIndex == index} }
                val scale by animateFloatAsState(targetValue = if(isFirstItem) 1.2f else 1f,
                    label = "scale animation"
                )
                Card(
                    modifier = Modifier
                        .padding(start = 30.dp, end = 10.dp)
                        .size(80.dp)
                        .scale(scale = scale)
                        .border(
                            if (isFirstItem) 2.dp else 0.dp,
                            if (isFirstItem) Color.White else Color.Transparent,
                            RoundedCornerShape(15.dp)
                        )
                        ,
                    colors = CardDefaults.cardColors(Color.Blue),
                    shape = RoundedCornerShape(15.dp),

                    ) {
                    Text(text = "$index")
                }
            }
        }
    }
}

I am actually just calculating if the offset of very first visible item goes out of the bounds of viewport and if it does then scrolling the lazy list to that item.

Jetpack Compose – 修改滚动行为以保持焦点在屏幕上的固定位置

huangapple
  • 本文由 发表于 2023年7月3日 16:06:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76602896.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定