Stronicowanie umożliwia użytkownikom przesuwanie palcem w poziomie lub pionie między różnymi stronami na pełnym ekranie na urządzeniach z Wear OS. Typowe zastosowania to m.in. przełączanie się między danymi treningowymi a elementami sterującymi multimediami w aplikacji do ćwiczeń lub przechodzenie przez wielostronicowe procesy.
W Compose for Wear OS Material 3 komponenty HorizontalPagerScaffold i VerticalPagerScaffold koordynują układ stronicowania, automatycznie pozycjonują wskaźnik strony i zarządzają przejściami za pomocą TimeText.
Każda strona jest opakowana w komponent AnimatedPage, który stosuje skalowanie, zaokrąglanie rogów i efekty przyciemnienia podczas przechodzenia stron na okrągłym wyświetlaczu.
Poniższa animacja pokazuje, jak HorizontalPagerScaffold i AnimatedPage
skalują i animują strony podczas przesuwania w poziomie:
Hierarchia szkieletowa na potrzeby stronicowania
Podczas projektowania układów ekranów z podziałem na strony w Material 3 – niezależnie od tego, czy przewijasz w lewo lub w prawo (HorizontalPager), czy w górę lub w dół (VerticalPager) – używaj tej hierarchii komponentów od kontenera zewnętrznego do treści wewnętrznej:
AppScaffold: najbardziej zewnętrzny kontener w katalogu głównym aplikacji (używaj tylko jednego na aplikację). Przytrzymuje globalną nakładkęTimeText, dzięki czemu zegar pozostaje nieruchomy u góry ekranu podczas przejść między stronami i gestów odrzucania przez przesunięcie.HorizontalPagerScaffoldlubVerticalPagerScaffold: umieszczony wAppScaffoldna poziomie pagera. Koordynuje przejścia międzyTimeTextaHorizontalPageIndicatorlubVerticalPageIndicator.HorizontalPagerlubVerticalPager: kontener stronicowania podstawowego, który zarządza gestami przesuwania, fizyką rzucania i przyciąganiem danych wejściowych z pokrętła za pomocą udostępnionego elementuPagerState.AnimatedPage: umieszczony w funkcji lambda treści strony pagera. Zawiera każdą stronę, aby zastosować animacje przejścia Material 3 (efekty skalowania i przesłony) na podstawie przesunięcia strony wPagerState.ScreenScaffold: umieszczony wewnątrzAnimatedPagena każdej stronie. Każda strona może zawierać własną listę z możliwością przewijania w pionie (np.TransformingLazyColumn) lub własnyEdgeButton. ZagnieżdżenieScreenScaffoldna każdej stronie zapewnia, że wskaźniki przewijania w pionie, przyciski krawędziowe icontentPaddingnależą do tej konkretnej strony i płynnie się z nią animują.
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)
Wdrażanie podziału na strony w poziomie
Aby zaimplementować poziomy pager w Material 3, zagnieźdź HorizontalPagerScaffold, HorizontalPager, AnimatedPage i ScreenScaffold w AppScaffold aplikacji.
Użyj PagerScaffoldDefaults.snapWithSpringFlingBehavior dla
flingBehavior, aby zastosować fizykę ruchu sprężynowego Material 3 i elastyczne przyciąganie strony (HighSnapPositionalThreshold). Domyślnie HorizontalPager wyłącza przewijanie strony za pomocą obrotu (rotaryScrollableBehavior = null), umożliwiając przewijanie list pionowych (np. TransformingLazyColumn) na aktywnej stronie za pomocą obrotowego pokrętła lub ramki.
Poniższy przykład pokazuje kompletną konfigurację 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") } } } } } } } } }
Jeśli strona w pagerze poziomym zawiera element TransformingLazyColumn, utwórz osobny element rememberTransformingLazyColumnState() w zakresie tej strony i przekaż go do wewnętrznych elementów ScreenScaffold i 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") } } } } } } } } }
Wdrażanie miejsca podziału na strony w pionie
Pionowy pager umożliwia użytkownikom przesuwanie palcem w górę i w dół między stronami lub przechodzenie między nimi za pomocą obrotowego przycisku bocznego lub ramki zegarka.
W przeciwieństwie do HorizontalPager, VerticalPager domyślnie włącza przyciąganie obrotowe strony (RotaryScrollableDefaults.snapBehavior(state)). Przekaż PagerScaffoldDefaults.snapWithSpringFlingBehavior do flingBehavior i otocz każdą stronę tagami AnimatedPage i 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") } } } } } } }
Dostosowywanie działania pagera
Możesz dostosować czułość przyciągania HorizontalPagerScaffold i VerticalPagerScaffold do potrzeb interakcji w aplikacji.
Dostosowywanie czułości przyciągania podczas treningów
Podczas treningów lub aktywności o dużej intensywności, gdy użytkownik ma ograniczoną kontrolę nad ruchami dużymi, przypadkowe dotknięcia lub niewielkie obroty pokrętła mogą nieumyślnie przełączać strony. W przypadku tych ekranów skonfiguruj pager z niską czułością przyciągania:
- Przesuń
PagerDefaults.snapFlingBehavioromaxFlingPages = 0isnapPositionalThreshold = PagerScaffoldDefaults.LowSnapPositionalThreshold, aby przewrócić stronę. Wymaga to celowego przeciągnięcia po większej części ekranu. - Jeśli włączysz przyciąganie strony podczas obracania, ustaw wartość
snapSensitivity = RotaryScrollableDefaults.LowSnapSensitivityw poluRotaryScrollableDefaults.snapBehavior, aby wymagać większego obrotu przed przyciągnięciem do następnej strony.
@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 } } } } } }
Pełne przykłady implementacji znajdziesz w Pager.kt w repozytorium android/snippets i PagerScaffoldSample.kt w repozytorium AndroidX.