Постраничная прокрутка позволяет пользователям переходить между отдельными полноэкранными страницами на устройствах Wear OS, проводя пальцем по экрану по горизонтали или вертикали. Например, с помощью пролистывания можно переключаться между показателями тренировки и элементами управления мультимедиа в приложении для занятий спортом или переходить между страницами.
В Compose для Wear OS Material 3 компоненты HorizontalPagerScaffold и VerticalPagerScaffold координируют макет пейджера, автоматически размещая индикатор страниц и управляя переходами с помощью TimeText.
Каждая страница заключена в компонуемый элемент AnimatedPage, который применяет масштабирование, скругление углов и эффекты затемнения при переходе между страницами на круглом экране.
На следующей анимации показано, как HorizontalPagerScaffold и AnimatedPage масштабируют и анимируют страницы при горизонтальных пролистываниях:
Иерархия для разбивки на страницы
При разработке макетов экранов с разбивкой на страницы в Material 3 (с пролистыванием влево или вправо (HorizontalPager) или вверх или вниз (VerticalPager)) используйте следующую иерархию компонентов от внешнего контейнера до внутреннего контента:
AppScaffold– внешний контейнер в корне приложения (в приложении может быть только один такой контейнер). Он закрепляет оверлейTimeText, чтобы часы оставались вверху экрана при переходе между страницами и жестах смахивания.HorizontalPagerScaffoldилиVerticalPagerScaffold: размещается внутриAppScaffoldна уровне страницы. Он координирует переходы междуTimeTextиHorizontalPageIndicatorилиVerticalPageIndicator.HorizontalPagerилиVerticalPager. Контейнер пейджера Foundation, который управляет жестами пролистывания, физикой броска и привязкой вращающегося ввода с помощью общегоPagerState.AnimatedPage: размещается в лямбда-выражении для контента страницы пейджера. Он добавляет к каждой странице анимацию перехода Material 3 (эффекты масштабирования и затемнения) на основе смещения страницы вPagerState.ScreenScaffold: размещается внутриAnimatedPageна каждой отдельной странице. Поскольку на каждой странице может быть свой список с вертикальной прокруткой (например,TransformingLazyColumn) или свойEdgeButton, вложенный в каждую страницу элементScreenScaffoldгарантирует, что индикаторы вертикальной прокрутки, кнопки по краям иcontentPaddingотносятся к определенной странице и плавно анимируются вместе с ней.
AppScaffold (1 per app: anchors global TimeText)
└── HorizontalPagerScaffold / VerticalPagerScaffold (manages PageIndicator)
└── HorizontalPager / VerticalPager (manages PagerState & fling behavior)
└── AnimatedPage (applies scaling & scrim transitions per page)
└── ScreenScaffold (1 per page: ScrollIndicator & EdgeButton)
└── Page Content (Column or TransformingLazyColumn)
Как реализовать горизонтальную навигацию по страницам
Чтобы реализовать горизонтальный пейджер в Material 3, вложите HorizontalPagerScaffold, HorizontalPager, AnimatedPage и ScreenScaffold в AppScaffold приложения.
Используйте PagerScaffoldDefaults.snapWithSpringFlingBehavior для flingBehavior, чтобы применить физику пружинного движения Material 3 и адаптивное прилипание страницы (HighSnapPositionalThreshold). По умолчанию HorizontalPager отключает прокрутку страницы с помощью вращающегося элемента (rotaryScrollableBehavior = null), позволяя вращать заводную головку или безель, чтобы прокручивать вертикальные списки (например, TransformingLazyColumn) на активной странице.
Ниже приведен пример полной настройки HorizontalPagerScaffold:
@Composable fun HorizontalPagerScaffoldSample(navigateBack: () -> Unit) { AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPagerScaffold(pagerState = pagerState) { HorizontalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe left and right") if (page == 0) { Spacer(modifier = Modifier.height(16.dp)) Button(onClick = navigateBack) { Text("Exit") } } } } } } } } }
Если на странице, входящей в горизонтальный пейджер, есть элемент TransformingLazyColumn, создайте отдельный элемент rememberTransformingLazyColumnState() в области действия этой страницы и передайте его внутренним элементам ScreenScaffold и TransformingLazyColumn:
AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPagerScaffold(pagerState = pagerState) { HorizontalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState, ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding, ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( ListHeaderDefaults.minimumTopListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { Text(text = "Pager sample") } } item { Card( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( CardDefaults.minimumVerticalListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { if (page == 0) { Text(text = "Page #$page. Swipe right") } else { Text(text = "Page #$page. Swipe left and right") } } } } } } } } }
Как реализовать вертикальный пейджер
Вертикальный пейджер позволяет переходить между страницами, проводя пальцем вверх или вниз, а также с помощью вращающейся боковой кнопки или безеля часов.
В отличие от HorizontalPager, VerticalPager по умолчанию включает привязку страниц при повороте (RotaryScrollableDefaults.snapBehavior(state)). Передайте PagerScaffoldDefaults.snapWithSpringFlingBehavior в flingBehavior и оберните каждую страницу в AnimatedPage и ScreenScaffold:
@Composable fun VerticalPagerScaffoldSample() { AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPagerScaffold(pagerState = pagerState) { VerticalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe up and down") } } } } } } }
Как настроить поведение пейджера
Вы можете настроить чувствительность прилипания HorizontalPagerScaffold и VerticalPagerScaffold в соответствии с потребностями вашего приложения.
Как настроить чувствительность привязки для тренировок
Во время тренировок или других занятий, требующих активных движений, когда пользователь не может полностью контролировать движения, случайные прикосновения или небольшие повороты колесика Digital Crown могут привести к непреднамеренному переключению страниц. Для таких экранов настройте пейджер с низкой чувствительностью к привязке:
- Передайте
PagerDefaults.snapFlingBehaviorс параметрамиmaxFlingPages = 0иsnapPositionalThreshold = PagerScaffoldDefaults.LowSnapPositionalThreshold, чтобы для перелистывания страницы требовалось провести пальцем по большей части экрана. - Если вы включили привязку страниц при вращении, задайте значение
snapSensitivity = RotaryScrollableDefaults.LowSnapSensitivityвRotaryScrollableDefaults.snapBehavior, чтобы для перехода к следующей странице требовалось большее вращение.
@Composable fun HorizontalPagerScaffoldWithLowSensitivitySample(navigateBack: () -> Unit) { AppScaffold { val pagerState = rememberPagerState(pageCount = { 3 }) HorizontalPagerScaffold(pagerState = pagerState) { HorizontalPager( state = pagerState, flingBehavior = PagerDefaults.snapFlingBehavior( state = pagerState, maxFlingPages = 0, snapPositionalThreshold = PagerScaffoldDefaults.LowSnapPositionalThreshold, ), rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior( pagerState = pagerState, snapSensitivity = RotaryScrollableDefaults.LowSnapSensitivity, ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { // Page content } } } } } }
Примеры реализаций можно найти в Pager.kt в репозитории android/snippets и PagerScaffoldSample.kt в репозитории AndroidX.