返回

HorizontalPager 滑块重复触发:从 Accompanist 到 Foundation Compose 的迁移之路

Android

解决 HorizontalPager 滑块在从 Accompanist 迁移到 Foundation Compose 时重复触发的难题

问题溯源:LaunchedEffect 的不同实现

在从 Accompanist 迁移到 Foundation Compose 时,我们可能会遇到一个令人头疼的问题:HorizontalPager 滑块在手动滑动后会重复触发自动滑动逻辑。这种异常行为的根源在于 LaunchedEffect 的不同实现。在 Accompanist 中,LaunchedEffect 中启动的协程会在 recomposition 时被取消,但在 Foundation Compose 中却不会。

优雅解决:使用协程范围(coroutineScope)

为了解决这个问题,我们需要在 LaunchedEffect 中使用 coroutineScope.launch {} 来启动协程。这样,协程将在 recomposition 时被取消,从而避免重复触发自动滑动逻辑。

LaunchedEffect("${state.currentPage}") {
    coroutineScope.launch {
        delay(AUTO_SLIDER_DELAY)
        if (state.pageCount != 0) {
            var newPosition = state.currentPage + 1
            if (newPosition > sliderItems.size - 1) newPosition = 0
            state.animateScrollToPage(newPosition.mod(state.pageCount))
        }
    }
}

优化之道:利用 animateScrollTo()

在 HorizontalPager 中,我们可以使用 Modifier.animateScrollTo() 来代替 animateScrollToPage(),从而避免创建额外的 composable 函数。

HorizontalPager(
    state = state
) { page ->
    AsyncBlurryImage(
        imageUrl = imageUrl.value,
        contentScale = ContentScale.Crop,
        contentDescription = null,
        modifier = Modifier
            .aspectRatio(1.77f)
            .animateScrollTo(page)
    )
}

结论:问题终结

通过使用协程范围和利用 animateScrollTo(),我们巧妙地解决了 HorizontalPager 滑块重复触发的问题。这不仅消除了代码中的缺陷,而且使代码更加简洁高效。

常见问题解答

1. 为什么在 Accompanist 和 Foundation Compose 中 LaunchedEffect 的实现不同?

具体实现细节不同,这是两套库之间的内部分歧。

2. 除了使用协程范围,还有其他解决方法吗?

没有其他已知的解决方案。

3. 为什么需要在LaunchedEffect中使用"${state.currentPage}"?

这会触发LaunchedEffect在每次state.currentPage改变时重新运行。

4. 是否可以在HorizontalPager的子项中使用animateScrollTo()?

不行,只能在HorizontalPager本身使用。

5. 为什么使用coroutineScope.launch {}启动协程?

它确保协程在 recomposition 时被取消,从而防止重复触发。