Home > Software design >  How to animate offset in HorizontalPager?
How to animate offset in HorizontalPager?

Time:09-22

I have three cards in HorizontalPager and I want to animate its offset like this one when user scroll through pages.

val pagerState = rememberPagerState(pageCount = 3)
val currentIndex = pagerState.currentPage
HorizontalPager(
        state = pagerState,
        modifier = Modifier.fillMaxSize()
    ) { page ->
        Card(
            modifier = Modifier
                .fillMaxWidth(0.7f)
                .fillMaxHeight(0.7f)
                .padding(22.dp)
                .offset(y = if (currentIndex == page) 0.dp else 70.dp),
            shape = RoundedCornerShape(30.dp),
            elevation = 110.dp
        ) {}
    }

CodePudding user response:

You can calculate the offset using pagerState.currentPageOffset.

When you scroll the HorizontalPager, the currentPage will not change until you release the drag. When you scroll to the right, currentPageOffset increases from 0f to 1f, and when you scroll to the left, it decreases from 0f to -1f.

In my code, I calculate offset for each page:

  1. The offset of the current page should increase as we scroll left and right, so we can take absoluteValue.
  2. The left page offset should decrease as long as currentPageOffset changes from 0f to -1f.
  3. The right page offset should decrease while currentPageOffset increases from 0f to 1f.
@Composable
fun TestScreen() {
    val pagerState = rememberPagerState(pageCount = 3)
    val currentIndex = pagerState.currentPage
    val currentPageOffset = pagerState.currentPageOffset
    HorizontalPager(
        state = pagerState,
        modifier = Modifier.fillMaxSize()
    ) { page ->
        val offset = maxOffset * when (page) {
            currentIndex -> {
                currentPageOffset.absoluteValue
            }
            currentIndex - 1 -> {
                1   currentPageOffset.coerceAtMost(0f)
            }
            currentIndex   1 -> {
                1 - currentPageOffset.coerceAtLeast(0f)
            }
            else -> {
                1f
            }
        }
        Card(
            modifier = Modifier
                .fillMaxWidth(0.7f)
                .fillMaxHeight(0.7f)
                .padding(22.dp)
                .offset(y = offset),
            shape = RoundedCornerShape(30.dp),
            elevation = 110.dp
        ) {}
    }
}

private val maxOffset = 70.dp

Result:

  • Related