La paginación permite a los usuarios deslizar el dedo horizontal o verticalmente entre páginas distintas de pantalla completa en dispositivos Wear OS. Los casos de uso comunes incluyen deslizar el dedo entre las métricas de entrenamiento y los controles multimedia en una app de ejercicios, o bien avanzar por flujos de varias páginas.
En Compose para Wear OS Material 3, HorizontalPagerScaffold y VerticalPagerScaffold coordinan el diseño del paginador, posicionan automáticamente el indicador de página y administran las transiciones con TimeText.
Cada página se incluye en un elemento AnimatedPage componible, que aplica efectos de escala, transformación de esquinas redondeadas y scrim a medida que las páginas realizan la transición en la pantalla redonda.
En la siguiente animación, se muestra cómo HorizontalPagerScaffold y AnimatedPage escalan y animan las páginas durante los deslizamientos horizontales:
Jerarquía de andamios para la paginación
Cuando diseñes diseños de pantalla paginados en Material 3, ya sea que deslices el dedo hacia la izquierda o la derecha (HorizontalPager) o hacia arriba o hacia abajo (VerticalPager), usa la siguiente jerarquía de componentes, desde el contenedor exterior hasta el contenido interior:
AppScaffold: Es el contenedor más externo en la raíz de tu app (usa solo uno por app). Ancla la superposición globalTimeTextpara que el reloj permanezca fijo en la parte superior de la pantalla durante las transiciones de página y los gestos de deslizamiento para descartar.HorizontalPagerScaffoldoVerticalPagerScaffold: Se coloca dentro deAppScaffolda nivel del paginador. Coordina las transiciones entreTimeTextyHorizontalPageIndicatoroVerticalPageIndicator.HorizontalPageroVerticalPager: Es el contenedor de paginación básico que administra los gestos de deslizamiento, la física de arrastre y el ajuste de entrada rotativa con unPagerStatecompartido.AnimatedPage: Se coloca dentro de la expresión lambda del contenido de la página del paginador. Envuelve cada página individual para aplicar animaciones de transición de Material 3 (efectos de ajuste y velado) según el desplazamiento de la página enPagerState.ScreenScaffold: Se coloca dentro deAnimatedPagepara cada página individual. Dado que cada página puede contener su propia lista desplazable verticalmente (como unTransformingLazyColumn) o su propioEdgeButton, anidarScreenScaffolddentro de cada página garantiza que los indicadores de desplazamiento vertical, los botones de borde ycontentPaddingpertenezcan a esa página específica y se animen sin problemas con ella.
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)
Implementa un carrusel horizontal
Para implementar un paginador horizontal en Material 3, anida HorizontalPagerScaffold, HorizontalPager, AnimatedPage y ScreenScaffold dentro del AppScaffold de tu app.
Usa PagerScaffoldDefaults.snapWithSpringFlingBehavior para que flingBehavior aplique la física de movimiento de resorte de Material 3 y el ajuste de página responsivo (HighSnapPositionalThreshold). De forma predeterminada, HorizontalPager inhabilita el desplazamiento de página rotatorio (rotaryScrollableBehavior = null), lo que permite que la entrada de la corona o el bisel rotatorio desplace listas verticales (como un TransformingLazyColumn) dentro de la página activa.
En el siguiente ejemplo, se muestra una configuración completa de 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") } } } } } } } } }
Si una página dentro de tu paginador horizontal contiene un TransformingLazyColumn, crea un rememberTransformingLazyColumnState() independiente dentro del alcance de esa página y pásalo a los ScreenScaffold y TransformingLazyColumn internos:
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") } } } } } } } } }
Implementa un carrusel vertical
Un localizador vertical permite a los usuarios deslizar el dedo hacia arriba y hacia abajo entre las páginas o recorrerlas con el botón lateral giratorio o el bisel del reloj.
A diferencia de HorizontalPager, VerticalPager habilita el ajuste rotatorio de páginas de forma predeterminada (RotaryScrollableDefaults.snapBehavior(state)). Pasa PagerScaffoldDefaults.snapWithSpringFlingBehavior a flingBehavior y envuelve cada página en AnimatedPage y 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") } } } } } } }
Personaliza el comportamiento del paginador
Puedes personalizar la sensibilidad de ajuste de HorizontalPagerScaffold y VerticalPagerScaffold para que coincida con las necesidades de interacción de tu app.
Cómo ajustar la sensibilidad de los ajustes para los entrenamientos
Durante los entrenamientos o las actividades de alto movimiento en los que el control de la motricidad gruesa del usuario es limitado, los toques accidentales o las rotaciones leves de la corona pueden cambiar de página sin intención. Para estas pantallas, configura el paginador con una sensibilidad de ajuste baja:
- Pasa
PagerDefaults.snapFlingBehaviorconmaxFlingPages = 0ysnapPositionalThreshold = PagerScaffoldDefaults.LowSnapPositionalThreshold, por lo que se requiere un arrastre deliberado en una porción más grande de la pantalla para pasar la página. - Si habilitas el ajuste de página con el selector, configura
snapSensitivity = RotaryScrollableDefaults.LowSnapSensitivityenRotaryScrollableDefaults.snapBehaviorpara requerir más rotación antes de ajustar la página siguiente.
@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 } } } } } }
Para ver implementaciones de muestras completas, consulta Pager.kt en el repositorio de android/snippets y PagerScaffoldSample.kt en el repositorio de AndroidX.