You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose中实现无限垂直轮播?

在Jetpack Compose中实现无限垂直轮播效果

下面是一种基于LazyColumn的实现方案,能实现无缝的无限垂直滚动(支持自动滚动和手动滚动),解决Accompanist Pager无法满足无限循环的问题:

核心思路

通过扩展数据源(将原始数据重复多份),结合LazyListState控制滚动位置,在滚动到边界时重置到中间的原始数据区域,视觉上实现无缝循环。

完整代码实现

1. 定义数据模型(示例)

data class BannerItem(val id: Int, val content: String)

2. 无限轮播组件

@Composable
fun InfiniteVerticalCarousel(
    items: List<BannerItem>,
    modifier: Modifier = Modifier,
    autoScrollDelay: Long = 3000,
    itemContent: @Composable (BannerItem) -> Unit
) {
    require(items.isNotEmpty()) { "Items list can't be empty" }

    // 扩展数据源:首尾各追加一份原始数据,实现滚动衔接
    val extendedItems = remember(items) { items + items + items }
    val listState = rememberLazyListState(initialFirstVisibleItemIndex = items.size)

    // 自动滚动逻辑
    LaunchedEffect(Unit) {
        while (true) {
            delay(autoScrollDelay)
            listState.animateScrollToItem(listState.firstVisibleItemIndex + 1)
        }
    }

    // 滚动边界重置,实现无限循环
    LaunchedEffect(listState.firstVisibleItemIndex) {
        when {
            // 滚动到扩展数据的后半段末尾,重置到中间原始数据区域
            listState.firstVisibleItemIndex >= items.size * 2 -> {
                listState.scrollToItem(items.size)
            }
            // 滚动到扩展数据的前半段开头,重置到中间原始数据区域
            listState.firstVisibleItemIndex < items.size -> {
                listState.scrollToItem(items.size)
            }
        }
    }

    LazyColumn(
        state = listState,
        modifier = modifier,
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(extendedItems.size) { index ->
            itemContent(extendedItems[index])
        }
    }
}

3. 使用示例

@Composable
fun CarouselDemo() {
    val bannerItems = listOf(
        BannerItem(1, "Banner 1"),
        BannerItem(2, "Banner 2"),
        BannerItem(3, "Banner 3")
    )

    InfiniteVerticalCarousel(
        items = bannerItems,
        modifier = Modifier
            .fillMaxWidth()
            .height(200.dp)
            .clip(RoundedCornerShape(12.dp))
    ) { item ->
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(
                    when (item.id % 3) {
                        1 -> Color(0xFF667EEA)
                        2 -> Color(0xFF8B5CF6)
                        else -> Color(0xFFEC4899)
                    }
                ),
            contentAlignment = Alignment.Center
        ) {
            Text(
                text = item.content,
                color = Color.White,
                fontSize = 24.sp,
                fontWeight = FontWeight.Bold
            )
        }
    }
}

关键细节说明

  • 扩展数据源:重复三次原始数据,确保滚动到末尾时,后续内容和开头完全一致,视觉上无断层;初始位置设为中间的原始数据,避免启动时触发重置。
  • 自动滚动:通过LaunchedEffect创建无限循环,每隔指定时间执行一次滚动动画,可通过autoScrollDelay调整滚动间隔。
  • 边界重置:当滚动到扩展数据的首尾区域时,直接跳转到中间的原始数据位置,由于前后内容一致,用户不会察觉到跳转动作。
  • 手动滚动支持:组件同时支持用户手动上下滚动,滚动到边界时同样会触发位置重置,保持无限循环效果。

内容的提问来源于stack exchange,提问作者willy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 06:10:15