Чтобы пролистывать контент влево и вправо или вверх и вниз, вы можете использовать составные элементы 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) ) } }

Применение эффектов прокрутки элементов к содержимому
Распространенным вариантом использования является использование положения прокрутки для применения эффектов к элементам пейджера. Чтобы узнать, насколько далеко страница находится от выбранной в данный момент страницы, вы можете использовать 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), beyondViewportPageCount = 10, flingBehavior = fling ) { PagerSampleItem(page = it) } }
Создайте автоматически продвигающийся пейджер
В этом разделе описывается, как создать автоматически перемещающийся пейджер с индикаторами страниц в Compose. Коллекция элементов автоматически прокручивается по горизонтали, но пользователи также могут вручную перемещаться между элементами. Если пользователь взаимодействует с пейджером, он останавливает автоматическое продвижение.
Базовый пример
Следующие фрагменты вместе создают базовую реализацию автоматического пейджера с визуальным индикатором, в котором каждая страница отображается разным цветом:
@Composable fun AutoAdvancePager(pageItems: List<Color>, modifier: Modifier = Modifier) { Box(modifier = Modifier.fillMaxSize()) { val pagerState = rememberPagerState(pageCount = { pageItems.size }) val pagerIsDragged by pagerState.interactionSource.collectIsDraggedAsState() val pageInteractionSource = remember { MutableInteractionSource() } val pageIsPressed by pageInteractionSource.collectIsPressedAsState() // Stop auto-advancing when pager is dragged or one of the pages is pressed val autoAdvance = !pagerIsDragged && !pageIsPressed if (autoAdvance) { LaunchedEffect(pagerState, pageInteractionSource) { while (true) { delay(2000) val nextPage = (pagerState.currentPage + 1) % pageItems.size pagerState.animateScrollToPage(nextPage) } } } HorizontalPager( state = pagerState ) { page -> Text( text = "Page: $page", textAlign = TextAlign.Center, modifier = modifier .fillMaxSize() .background(pageItems[page]) .clickable( interactionSource = pageInteractionSource, indication = LocalIndication.current ) { // Handle page click } .wrapContentSize(align = Alignment.Center) ) } PagerIndicator(pageItems.size, pagerState.currentPage) } }
Ключевые моменты о коде
- Функция
AutoAdvancePager
создает горизонтальное представление страниц с автоматическим продвижением. В качестве входных данных он принимает список объектовColor
, которые используются в качестве цветов фона для каждой страницы. -
pagerState
создается с помощьюrememberPagerState
, который хранит состояние пейджера. -
pagerIsDragged
иpageIsPressed
отслеживают взаимодействие с пользователем. -
LaunchedEffect
автоматически перемещает пейджер каждые две секунды, если пользователь не перетаскивает пейджер или не нажимает одну из страниц. -
HorizontalPager
отображает список страниц, каждая из которых имеет составнойText
, отображающий номер страницы. Модификатор заполняет страницу, устанавливает цвет фона изpageItems
и делает страницу кликабельной.
@Composable fun PagerIndicator(pageCount: Int, currentPageIndex: Int, modifier: Modifier = Modifier) { Box(modifier = Modifier.fillMaxSize()) { Row( modifier = Modifier .wrapContentHeight() .fillMaxWidth() .align(Alignment.BottomCenter) .padding(bottom = 8.dp), horizontalArrangement = Arrangement.Center ) { repeat(pageCount) { iteration -> val color = if (currentPageIndex == iteration) Color.DarkGray else Color.LightGray Box( modifier = modifier .padding(2.dp) .clip(CircleShape) .background(color) .size(16.dp) ) } } } }
Ключевые моменты о коде
- В качестве корневого элемента используется составной элемент
Box
.- Внутри
Box
компонуемый элементRow
размещает индикаторы страниц по горизонтали.
- Внутри
- Пользовательский индикатор страницы отображается в виде ряда кружков, где каждый
Box
, обрезанныйcircle
представляет страницу. - Круг текущей страницы окрашен в
DarkGray
, а остальные круги — вLightGray
. ПараметрcurrentPageIndex
определяет, какой круг отображается темно-серым цветом.
Результат
В этом видео показан базовый пейджер с автоматическим продвижением из предыдущих фрагментов:
Пока рекомендаций нет.
Попытайтесь войти в свой аккаунт Google.