Чтобы пролистывать контент влево и вправо или вверх и вниз, вы можете использовать составные элементы HorizontalPager
и VerticalPager
соответственно. Эти составные элементы имеют функции, аналогичные ViewPager
в системе представлений. По умолчанию HorizontalPager
занимает всю ширину экрана, VerticalPager
— всю высоту, а пейджеры перебрасывают только одну страницу за раз. Все эти значения по умолчанию можно настроить.
HorizontalPager
Чтобы создать пейджер, который прокручивается по горизонтали влево и вправо, используйте HorizontalPager
:
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
: 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) ) } }
![Пейджер с круговым индикатором под содержимым](https://developer.android.com/static/develop/ui/compose/images/layouts/pager/indicator.png?authuser=8&hl=ru)
Применение эффектов прокрутки элементов к содержимому
Распространенным вариантом использования является использование положения прокрутки для применения эффектов к элементам пейджера. Чтобы узнать, насколько далеко страница находится от выбранной в данный момент страницы, вы можете использовать PagerState.currentPageOffsetFraction
. Затем вы можете применить эффекты трансформации к своему контенту в зависимости от расстояния от выбранной страницы.
Например, чтобы настроить непрозрачность элементов в зависимости от того, насколько далеко они находятся от центра, измените 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), beyondBoundsPageCount = 10, flingBehavior = fling ) { PagerSampleItem(page = it) } }{% дословно %}
Рекомендуется для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- ConstraintLayout в Compose
- Графические модификаторы
- Перенос
CoordinatorLayout
в Compose