【问题标题】:Jetpack Compose LazyRow - Center selected itemJetpack Compose LazyRow - 将所选项目居中
【发布时间】:2022-11-08 04:05:17
【问题描述】:

如何计算选定项目在 LazyRow 中的位置并将其用于在屏幕上居中项目? 这些项目将根据其内容具有不同的大小。

如果我选择lazyListState.animateScrollToItem(index),则所选项目将位于 LazyRow 的左侧。

我想要实现的是让所选项目像这样居中

我目前拥有的代码:

@Composable
fun Test() {
    Column {
        TestRow(listOf("Angola", "Bahrain", "Afghanistan", "Denmark", "Egypt", "El Salvador", "Fiji", "Japan", "Kazakhstan", "Kuwait", "Laos", "Mongolia"))
        TestRow(listOf("Angola", "Bahrain", "Afghanistan"))
    }
}

@OptIn(ExperimentalSnapperApi::class)
@Composable
fun TestRow(items: List<String>) {
    val selectedIndex = remember { mutableStateOf(0) }
    val lazyListState = rememberLazyListState()
    val coroutineScope = rememberCoroutineScope()

    LazyRow(
        modifier = Modifier.fillMaxWidth(),
        state = lazyListState,
        horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally),
        contentPadding = PaddingValues(horizontal = 12.dp),
        flingBehavior = rememberSnapperFlingBehavior(
            lazyListState = lazyListState,
            snapOffsetForItem = SnapOffsets.Start
        )
    ) {
        itemsIndexed(items) { index, item ->
            TestItem(
                content = item,
                isSelected = index == selectedIndex.value,
                onClick = {
                    selectedIndex.value = index
                    coroutineScope.launch {
                        lazyListState.animateScrollToItem(index)
                    }
                }
            )
        }
    }
}

@Composable
fun TestItem(
    content: String,
    isSelected: Boolean,
    onClick: () -> Unit
) {
    Button(
        modifier = Modifier.height(40.dp),
        colors = ButtonDefaults.buttonColors(
            backgroundColor = if (isSelected) Color.Green else Color.Yellow,
            contentColor = Color.Black
        ),
        elevation = null,
        shape = RoundedCornerShape(5.dp),
        contentPadding = PaddingValues(0.dp),
        onClick = onClick
    ) {
        Text(
            modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
            text = (content).uppercase(),
        )
    }
}

代码horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally) 是为了确保当没有足够的项目进行滚动时,LazyRow 将所有项目居中。 带有 3 个项目的示例:

我已经尝试过在类似问题上发布的各种建议,但没有找到解决方案。 jetpack-compose-lazylist-possible-to-zoom-the-center-item how-to-focus-a-invisible-item-in-lazycolumn-on-jetpackcompose /jetpack-compose-make-the-first-element-in-a-lazyrow-be-aligned-to-the-center-o

【问题讨论】:

    标签: android kotlin android-jetpack-compose android-jetpack-compose-list


    【解决方案1】:

    我找到了一个适合我需要的解决方案,因为我不希望导航到选定的项目,而无法看到它。

    此解决方案无法将屏幕上不可见的项目居中。

    coroutineScope.launch {
                    val itemInfo = lazyListState.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index }
                    if (itemInfo != null) {
                        val center = lazyListState.layoutInfo.viewportEndOffset / 2
                        val childCenter = itemInfo.offset + itemInfo.size / 2
                        lazyListState.animateScrollBy((childCenter - center).toFloat())
                    } else {
                        lazyListState.animateScrollToItem(index)
                    }
                }
    

    【讨论】:

    • 感谢您分享这一点。按预期工作。真是天才,但我不禁觉得,一定有更简单的方法……
    【解决方案2】:

    改进@Markram 答案

    您可以创建“LazyListState”的扩展:

    fun LazyListState.animateScrollAndCentralizeItem(index: Int, scope: CoroutineScope) {
        val itemInfo = this.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index }
        scope.launch {
            if (itemInfo != null) {
                val center = this@animateScrollAndCentralizeItem.layoutInfo.viewportEndOffset / 2
                val childCenter = itemInfo.offset + itemInfo.size / 2
                this@animateScrollAndCentralizeItem.animateScrollBy((childCenter - center).toFloat())
            } else {
                this@animateScrollAndCentralizeItem.animateScrollToItem(index)
            }
        }
    }
    

    然后直接在你的 Composable 中使用它:

    val coroutineScope = rememberCoroutineScope()
    coroutineScope.launch {
        listState.animateScrollAndCentralizeItem(index , this)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-09-26
      • 2021-11-27
      • 1970-01-01
      • 2022-08-03
      • 2020-12-22
      • 1970-01-01
      • 1970-01-01
      • 2020-08-16
      相关资源
      最近更新 更多