Функция постраничной навигации позволяет пользователям переключаться между отдельными полноэкранными страницами на устройствах Wear OS с помощью свайпов по горизонтали или вертикали. Типичные сценарии использования включают переключение между показателями тренировки и элементами управления мультимедиа в приложении для тренировок, а также пошаговое перемещение по многостраничным сценариям.
В Compose for Wear OS Material 3, HorizontalPagerScaffold и VerticalPagerScaffold координируют компоновку пейджера, автоматически позиционируя индикатор страницы и управляя переходами с помощью TimeText . Каждая страница заключена в компонент AnimatedPage , который применяет масштабирование, изменение скругленных углов и эффекты затемнения при переходе страниц по круглому экрану.
Следующая анимация демонстрирует, как HorizontalPagerScaffold и AnimatedPage масштабируют и анимируют страницы при горизонтальном свайпе:
Иерархическая структура для постраничной навигации
При разработке макетов экранов с постраничной разбивкой в Material 3 — независимо от того, используется ли свайп влево или вправо ( HorizontalPager ) или вверх или вниз ( VerticalPager ) — используйте следующую иерархию компонентов от внешнего контейнера к внутреннему содержимому:
-
AppScaffold: Самый внешний контейнер в корне вашего приложения (используйте только один на приложение). Он закрепляет глобальное наложениеTimeText, благодаря чему часы остаются неподвижными в верхней части экрана во время переходов между страницами и жестов смахивания для закрытия. -
HorizontalPagerScaffoldилиVerticalPagerScaffold: Размещается внутриAppScaffoldна уровне пейджера. Координирует переходы междуTimeTextиHorizontalPageIndicatorилиVerticalPageIndicator. -
HorizontalPagerилиVerticalPager: базовый контейнер пейджера, который управляет жестами смахивания, физикой броска и привязкой к вращающемуся вводу с помощью общегоPagerState. -
AnimatedPage: Размещается внутри лямбда-функции содержимого страницы пейджера. Она оборачивает каждую отдельную страницу, применяя анимации перехода Material 3 (масштабирование и эффекты затемнения) в зависимости от смещения страницы вPagerState. -
ScreenScaffold: Размещается внутриAnimatedPageдля каждой отдельной страницы. Поскольку каждая страница может содержать собственный список с вертикальной прокруткой (например,TransformingLazyColumn) или собственнуюEdgeButton, вложенностьScreenScaffoldвнутри каждой страницы гарантирует, что индикаторы вертикальной прокрутки, кнопки EdgeButton и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 в соответствии с потребностями взаимодействия вашего приложения.
Отрегулируйте чувствительность привязки для тренировок.
Во время тренировок или интенсивных физических нагрузок, когда крупная моторика пользователя ограничена, случайные касания или небольшие повороты колесика могут непреднамеренно переключать страницы. Для таких экранов настройте пейджер с низкой чувствительностью к щелчкам:
- Передайте в
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.