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

如何在Jetpack Compose中实现垂直方向无限滚动轮播效果

循环LazyColumn(类时间选择器顺滑滚动效果)实现方案

核心实现原理

抛弃手动跳转列表位置的实现思路,通过虚拟长列表+索引取模映射真实数据的方式,完全避免滚动到边界时的跳转操作,天然实现顺滑的无限循环效果。

具体实现步骤

  • 第一步:定义真实数据源,以0~59的时间选择场景为例,真实条目总数actualItemCount = 60
  • 第二步:给LazyColumn设置足够大的虚拟总长度(如Int.MAX_VALUE),该长度足够用户连续滚动数十万次不会碰到边界,不需要做任何边界判断处理
  • 第三步:所有位置的条目内容通过index % actualItemCount取模运算映射到真实数据源,无论索引数值多大,都会循环对应到0~59的真实条目

初始定位配置

为了让列表初始状态就显示第一个真实条目,同时上下都有足够的滚动空间,直接将LazyListState的初始定位设置到虚拟列表的中间位置即可:

val lazyListState = rememberLazyListState(
    initialFirstVisibleItemIndex = Int.MAX_VALUE / 2
)

可选:滚动吸附适配

如果需要实现滚动停止后自动对齐选中条目的效果,可使用Compose 1.4及以上版本自带的snapFlingBehavior:

LazyColumn(
    state = lazyListState,
    flingBehavior = rememberSnapFlingBehavior(lazyListState = lazyListState),
    modifier = Modifier.height(180.dp) // 按需求设置固定高度,比如一屏显示3个60dp高的条目
) {
    items(Int.MAX_VALUE) { index ->
        val actualNum = index % actualItemCount
        // 自定义条目样式,可单独处理选中状态
        Text(
            text = "%02d".format(actualNum),
            modifier = Modifier
                .height(60.dp)
                .wrapContentHeight(),
            fontSize = if ((lazyListState.firstVisibleItemIndex + 1) == index) 24.sp else 18.sp,
            color = if ((lazyListState.firstVisibleItemIndex + 1) == index) Color.Black else Color.Gray
        )
    }
}

当前选中值获取

通过derivedStateOf监听当前居中的选中数值,避免不必要的重组:

val selectedNum by remember {
    derivedStateOf {
        // 假设一屏显示3个条目,第2个是居中选中位,可按实际显示行数调整偏移量
        val centerIndex = lazyListState.firstVisibleItemIndex + 1
        centerIndex % actualItemCount
    }
}

若条目高度不固定,可通过firstVisibleItemScrollOffset计算滚动偏移量,获取更精准的居中索引。

效果参考

循环时间选择器效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 22:24:03