Как анимировать смещение в горизонтальном пейджере?

#animation #android-jetpack-compose

Вопрос:

У меня есть три карты в HorizontalPager, и я хочу анимировать их смещение, как это, когда пользователь просматривает страницы.

 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
        ) {}
    }
 

Ответ №1:

Вы можете рассчитать смещение с помощью pagerState.currentPageOffset .

Когда вы прокручиваете HorizontalPager , currentPage изображение не изменится, пока вы не отпустите перетаскивание. При прокрутке вправо currentPageOffset увеличивается от 0f до 1f , а при прокрутке влево уменьшается от 0f до -1f .

В моем коде я вычисляю offset для каждой страницы:

  1. Смещение текущей страницы должно увеличиваться по мере прокрутки влево и вправо, чтобы мы могли взять absoluteValue .
  2. Смещение левой страницы должно уменьшаться по мере currentPageOffset изменения от 0f до -1f .
  3. Смещение правой страницы должно уменьшаться при currentPageOffset увеличении от 0f до 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
 

Результат: