Jetpack Compose中Column如何获取首尾可见项(无法使用LazyColumn)
获取Jetpack Compose Column中首尾可见小时项的方案
因为和自定义布局共享滚动状态导致无法使用LazyColumn,要获取Column里7天小时项的首尾可见项,可以通过监听每个项的布局位置+滚动状态计算来实现,具体步骤和修改后的代码如下:
1. 核心思路
- 给每个小时项添加布局位置监听,判断其是否处于滚动视图的可见范围内
- 通过滚动状态
ScrollState跟踪滚动位置,每次滚动时重置可见项状态,重新计算首尾可见项 - 用
MutableState保存首尾可见的时间值
2. 修改后的完整代码
ScheduleSidebar 组件
@Composable fun ScheduleSidebar( hourHeight: Dp, scrollState: ScrollState, modifier: Modifier = Modifier, label: @Composable (time: LocalTime) -> Unit = { HourLabel(time = it) }, ) { val startTime = LocalTime.MIN val firstVisibleTime = remember { mutableStateOf<LocalTime?>(null) } val lastVisibleTime = remember { mutableStateOf<LocalTime?>(null) } val density = LocalDensity.current // 每次滚动时重置首尾状态,确保重新计算 LaunchedEffect(scrollState.value) { firstVisibleTime.value = null lastVisibleTime.value = null } Column( modifier = modifier .verticalScroll(scrollState) ) { repeat(7) { day -> repeat(24) { hour -> val currentTime = startTime.plusHours(hour.toLong()) Box( modifier = Modifier .height(hourHeight) .onGloballyPositioned { coordinates -> val scrollY = scrollState.value val viewportHeight = with(density) { scrollState.layoutInfo.viewportSize.height.toDp().toPx().toInt() } val itemTop = coordinates.positionInParent().y.toInt() val itemBottom = itemTop + coordinates.size.height // 判断当前项是否在可见视口内 val isVisible = itemBottom > scrollY && itemTop < scrollY + viewportHeight if (isVisible) { // 更新第一个可见项:取最早的时间 if (firstVisibleTime.value == null || currentTime.isBefore(firstVisibleTime.value)) { firstVisibleTime.value = currentTime } // 更新最后一个可见项:取最晚的时间 if (lastVisibleTime.value == null || currentTime.isAfter(lastVisibleTime.value)) { lastVisibleTime.value = currentTime } } } ) { label(currentTime) } } } } // 示例:打印首尾可见时间(可根据需求替换为业务逻辑) LaunchedEffect(firstVisibleTime.value, lastVisibleTime.value) { println("第一个可见时间:${firstVisibleTime.value}") println("最后一个可见时间:${lastVisibleTime.value}") } }
HourLabel 组件(修复文本格式化问题)
@Composable fun HourLabel( time: LocalTime, modifier: Modifier = Modifier, ) { val timeText = remember(time) { time.format(DateTimeFormatter.ofPattern("HH:mm")) } Text( text = timeText, modifier = modifier .fillMaxHeight() .padding(4.dp) ) }
3. 使用说明
- 调用
ScheduleSidebar时,需要传入和自定义布局共享的ScrollState实例,比如:val sharedScrollState = rememberScrollState() ScheduleSidebar( hourHeight = 60.dp, scrollState = sharedScrollState ) // 自定义布局同样使用 sharedScrollState firstVisibleTime和lastVisibleTime保存了当前首尾可见的小时时间,可根据业务需求将其用于同步其他布局、显示当前时间范围等场景。
内容的提问来源于stack exchange,提问作者EliodeBeirut
相关产品推荐
相关产品推荐

