Пейджер в режиме создания сообщения

Чтобы пролистывать контент влево и вправо или вверх и вниз, вы можете использовать составные элементы HorizontalPager и VerticalPager соответственно. Эти составные элементы имеют функции, аналогичные ViewPager в системе представлений. По умолчанию HorizontalPager занимает всю ширину экрана, VerticalPager — всю высоту, а пейджеры перебрасывают только одну страницу за раз. Все эти значения по умолчанию можно настроить.

HorizontalPager

Чтобы создать пейджер, который прокручивается по горизонтали влево и вправо, используйте HorizontalPager :

Рисунок 1 . Демо HorizontalPager

// Display 10 items
val pagerState = rememberPagerState(pageCount = {
    10
})
HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier.fillMaxWidth()
    )
}

VerticalPager

Чтобы создать пейджер, который прокручивается вверх и вниз, используйте VerticalPager :

Рисунок 2 . Демо VerticalPager

// Display 10 items
val pagerState = rememberPagerState(pageCount = {
    10
})
VerticalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier.fillMaxWidth()
    )
}

Ленивое творчество

Страницы как в HorizontalPager , так и в VerticalPager компонуются и компонуются при необходимости лениво . Когда пользователь прокручивает страницы, компоновка удаляет все страницы, которые больше не нужны.

Загрузить больше страниц за кадром

По умолчанию пейджер загружает только видимые страницы на экране. Чтобы загружать больше страниц за кадром, установите для beyondBoundsPageCount значение выше нуля.

Прокрутите до элемента на пейджере

Чтобы прокрутить страницу до определенной страницы в пейджере, создайте объект PagerState с помощью rememberPagerState() и передайте его в качестве параметра state пейджеру. Вы можете вызвать PagerState#scrollToPage() в этом состоянии внутри CoroutineScope :

val pagerState = rememberPagerState(pageCount = {
    10
})
HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier
            .fillMaxWidth()
            .height(100.dp)
    )
}

// scroll to page
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
    coroutineScope.launch {
        // Call scroll to on pagerState
        pagerState.scrollToPage(5)
    }
}, modifier = Modifier.align(Alignment.BottomCenter)) {
    Text("Jump to Page 5")
}

Если вы хотите анимировать страницу, используйте функцию PagerState#animateScrollToPage() :

val pagerState = rememberPagerState(pageCount = {
    10
})

HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier
            .fillMaxWidth()
            .height(100.dp)
    )
}

// scroll to page
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
    coroutineScope.launch {
        // Call scroll to on pagerState
        pagerState.animateScrollToPage(5)
    }
}, modifier = Modifier.align(Alignment.BottomCenter)) {
    Text("Jump to Page 5")
}

Получайте уведомления об изменениях состояния страницы

PagerState имеет три свойства с информацией о страницах: currentPage , settledPage и targetPage .

  • currentPage : ближайшая к позиции привязки страница. По умолчанию позиция привязки находится в начале макета.
  • settledPage : номер страницы, когда анимация или прокрутка не выполняются. Оно отличается от свойства currentPage тем, что currentPage немедленно обновляется, если страница находится достаточно близко к положению привязки, а settledPage остается неизменным до тех пор, пока не завершится выполнение всех анимаций.
  • targetPage : предлагаемая позиция остановки для движения прокрутки.

Вы можете использовать функцию snapshotFlow , чтобы наблюдать за изменениями этих переменных и реагировать на них. Например, чтобы отправлять аналитическое событие при каждом изменении страницы, вы можете сделать следующее:

val pagerState = rememberPagerState(pageCount = {
    10
})

LaunchedEffect(pagerState) {
    // Collect from the a snapshotFlow reading the currentPage
    snapshotFlow { pagerState.currentPage }.collect { page ->
        // Do something with each page change, for example:
        // viewModel.sendPageSelectedEvent(page)
        Log.d("Page change", "Page changed to $page")
    }
}

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

Добавить индикатор страницы

Чтобы добавить индикатор на страницу, используйте объект PagerState , чтобы получить информацию о том, какая страница выбрана из числа страниц, и нарисуйте свой собственный индикатор.

Например, если вам нужен простой круговой индикатор, вы можете повторить количество кругов и изменить цвет круга в зависимости от того, выбрана ли страница, используя pagerState.currentPage :

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    modifier = Modifier.fillMaxSize()
) { page ->
    // Our page content
    Text(
        text = "Page: $page",
    )
}
Row(
    Modifier
        .wrapContentHeight()
        .fillMaxWidth()
        .align(Alignment.BottomCenter)
        .padding(bottom = 8.dp),
    horizontalArrangement = Arrangement.Center
) {
    repeat(pagerState.pageCount) { iteration ->
        val color = if (pagerState.currentPage == iteration) Color.DarkGray else Color.LightGray
        Box(
            modifier = Modifier
                .padding(2.dp)
                .clip(CircleShape)
                .background(color)
                .size(16.dp)
        )
    }
}

Пейджер с круговым индикатором под содержимым
Рисунок 3 . Пейджер с круговым индикатором под содержимым

Применение эффектов прокрутки элементов к содержимому

Распространенным вариантом использования является использование положения прокрутки для применения эффектов к элементам пейджера. Чтобы узнать, насколько далеко страница находится от выбранной в данный момент страницы, вы можете использовать PagerState.currentPageOffsetFraction . Затем вы можете применить эффекты трансформации к своему контенту в зависимости от расстояния от выбранной страницы.

Рисунок 4 . Применение преобразований к содержимому пейджера

Например, чтобы настроить непрозрачность элементов в зависимости от того, насколько далеко они находятся от центра, измените alpha с помощью Modifier.graphicsLayer для элемента внутри пейджера:

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(state = pagerState) { page ->
    Card(
        Modifier
            .size(200.dp)
            .graphicsLayer {
                // Calculate the absolute offset for the current page from the
                // scroll position. We use the absolute value which allows us to mirror
                // any effects for both directions
                val pageOffset = (
                    (pagerState.currentPage - page) + pagerState
                        .currentPageOffsetFraction
                    ).absoluteValue

                // We animate the alpha, between 50% and 100%
                alpha = lerp(
                    start = 0.5f,
                    stop = 1f,
                    fraction = 1f - pageOffset.coerceIn(0f, 1f)
                )
            }
    ) {
        // Card content
    }
}

Пользовательские размеры страниц

По умолчанию HorizontalPager и VerticalPager занимают всю ширину или полную высоту соответственно. Вы можете установить переменную pageSize для расчета Fixed , Fill (по умолчанию) или пользовательского расчета размера.

Например, чтобы установить страницу фиксированной ширины 100.dp :

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    pageSize = PageSize.Fixed(100.dp)
) { page ->
    // page content
}

Чтобы определить размер страниц в зависимости от размера области просмотра, используйте расчет пользовательского размера страницы. Создайте собственный объект PageSize и разделите availableSpace на три, учитывая расстояние между элементами:

private val threePagesPerViewport = object : PageSize {
    override fun Density.calculateMainAxisPageSize(
        availableSpace: Int,
        pageSpacing: Int
    ): Int {
        return (availableSpace - 2 * pageSpacing) / 3
    }
}

Заполнение контента

HorizontalPager и VerticalPager поддерживают изменение заполнения содержимого, что позволяет влиять на максимальный размер и выравнивание страниц.

Например, установка start отступа выравнивает страницы по направлению к концу:

Пейджер с начальным заполнением, показывающий содержимое, выровненное по направлению к концу

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(start = 64.dp),
) { page ->
    // page content
}

Установка одного и того же значения для start и end заполнения центрирует элемент по горизонтали:

Пейджер с начальным и конечным заполнением, показывающий содержимое по центру

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(horizontal = 32.dp),
) { page ->
    // page content
}

Установка end отступа выравнивает страницы по направлению к началу:

Пейджер с начальным и конечным заполнением, показывающий содержимое, выровненное по началу.

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(end = 64.dp),
) { page ->
    // page content
}

Вы можете установить top и bottom значения, чтобы добиться аналогичного эффекта для VerticalPager . Значение 32.dp используется здесь только в качестве примера; вы можете установить любое значение для каждого размера заполнения.

Настройте поведение прокрутки

Компонуемые элементы HorizontalPager и VerticalPager по умолчанию определяют, как жесты прокрутки работают с пейджером. Однако вы можете настроить и изменить значения по умолчанию, такие как pagerSnapDistance или flingBehavior .

Расстояние привязки

По умолчанию HorizontalPager и VerticalPager задают максимальное количество страниц, которые жест перелистывания может прокручивать на одну страницу за раз. Чтобы изменить это, установите pagerSnapDistance для flingBehavior :

val pagerState = rememberPagerState(pageCount = { 10 })

val fling = PagerDefaults.flingBehavior(
    state = pagerState,
    pagerSnapDistance = PagerSnapDistance.atMost(10)
)

Column(modifier = Modifier.fillMaxSize()) {
    HorizontalPager(
        state = pagerState,
        pageSize = PageSize.Fixed(200.dp),
        beyondViewportPageCount = 10,
        flingBehavior = fling
    ) {
        PagerSampleItem(page = it)
    }
}

{% дословно %} {% дословно %} {% дословно %} {% дословно %}