如何区分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
相关产品推荐
相关产品推荐

