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

如何区分Accompanist Pager的用户手势滚动与程序化滚动?

区分Accompanist Pager的用户手势滚动与程序化滚动

要实现仅在用户手势触发滚动时执行特定操作,核心是跟踪滚动的触发来源,以下是两种可行方案:

方案一:封装程序化滚动方法并标记状态

通过自定义扩展函数包裹原生的程序化滚动方法,在调用时标记当前为程序化滚动状态,监听页面变化时根据标记过滤操作。

示例代码:

val pagerState = rememberPagerState()
// 标记是否为程序化滚动
var isProgrammaticScroll by remember { mutableStateOf(false) }

// 封装animateScrollToPage的程序化版本
suspend fun PagerState.animateScrollToPageProgrammatic(page: Int, pageOffset: Float = 0f) {
    isProgrammaticScroll = true
    animateScrollToPage(page, pageOffset)
    isProgrammaticScroll = false
}

// 封装scrollToPage的程序化版本
fun PagerState.scrollToPageProgrammatic(page: Int, pageOffset: Float = 0f) {
    isProgrammaticScroll = true
    scrollToPage(page, pageOffset)
    isProgrammaticScroll = false
}

// 监听页面变化并过滤触发源
LaunchedEffect(pagerState) {
    snapshotFlow { pagerState.currentPage to pagerState.isScrollInProgress }
        .distinctUntilChanged()
        .collect { (currentPage, isScrolling) ->
            // 仅在滚动结束且非程序化滚动时执行操作
            if (!isScrolling && !isProgrammaticScroll) {
                AnalyticsService.sendPageSelectedEvent(currentPage)
            }
        }
}

// 使用封装后的方法执行程序化滚动
// scope.launch {
//     pagerState.animateScrollToPageProgrammatic(targetPage)
// }

VerticalPager(
    count = 10,
    state = pagerState,
) { page ->
    Text(text = "Page: $page")
}

方案二:通过InteractionSource捕获用户交互

利用Pager组件的interactionSource捕获用户触摸事件,结合页面状态判断是否为用户触发的滚动。

示例代码:

val pagerState = rememberPagerState()
val interactionSource = remember { MutableInteractionSource() }
// 标记是否为用户发起的滚动
var userInitiatedScroll by remember { mutableStateOf(false) }

// 监听用户触摸交互
LaunchedEffect(interactionSource) {
    interactionSource.interactions.collect { interaction ->
        when (interaction) {
            is PressInteraction.Press -> userInitiatedScroll = true
            is PressInteraction.Release, is PressInteraction.Cancel -> userInitiatedScroll = false
        }
    }
}

// 监听页面变化并执行操作
LaunchedEffect(pagerState) {
    snapshotFlow { pagerState.currentPage to pagerState.isScrollInProgress }
        .distinctUntilChanged()
        .collect { (currentPage, isScrolling) ->
            if (!isScrolling && userInitiatedScroll) {
                AnalyticsService.sendPageSelectedEvent(currentPage)
            }
        }
}

VerticalPager(
    count = 10,
    state = pagerState,
    interactionSource = interactionSource
) { page ->
    Text(text = "Page: $page")
}

注意事项

  • 方案一要求所有程序化滚动必须使用封装后的方法,避免直接调用原生方法导致标记失效。
  • 方案二依赖触摸事件捕获,对于快速连续滚动等边缘场景,可能需要额外处理状态同步逻辑。

内容的提问来源于stack exchange,提问作者J. Doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 13:20:15