分頁功能可讓使用者在 Wear OS 裝置上,以水平或垂直方向滑動,切換不同的全螢幕頁面。常見用途包括在運動應用程式中滑動切換運動指標和媒體控制項,或是逐步完成多頁面流程。
在 Wear OS Material 3 的 Compose 中,HorizontalPagerScaffold 和 VerticalPagerScaffold 會協調分頁器版面配置,自動定位頁面指標,並使用 TimeText 管理轉場效果。每個頁面都會包裝在 AnimatedPage 可組合函式中,在頁面於圓形螢幕上轉場時,套用縮放、圓角變形和半透明效果。
以下動畫顯示 HorizontalPagerScaffold 和 AnimatedPage 如何在水平滑動期間縮放及動畫化頁面:
分頁的架構階層
在 Material 3 中設計分頁畫面版面配置時,無論是向左或向右滑動 (HorizontalPager),還是向上或向下滑動 (VerticalPager),請使用下列元件階層,從外部容器到內部內容:
AppScaffold:應用程式根層級的最外層容器 (每個應用程式只能使用一個)。這項功能會錨定全域TimeText疊加層,讓時鐘在頁面轉場和滑動關閉手勢期間,保持在畫面頂端。HorizontalPagerScaffold或VerticalPagerScaffold:放置在呼叫器層級的AppScaffold內。協調TimeText與HorizontalPageIndicator或VerticalPageIndicator之間的轉場效果。HorizontalPager或VerticalPager:基礎分頁容器,可使用共用的PagerState管理滑動手勢、快速滑動物理效果和旋轉輸入的對齊。AnimatedPage:放置在呼叫器頁面內容 lambda 內。這個函式會包裝每個個別頁面,根據頁面在PagerState中的偏移量,套用 Material 3 轉場動畫 (縮放和半透明效果)。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 中實作橫向頁面控制項,請在應用程式的 AppScaffold 中,巢狀內嵌 HorizontalPagerScaffold、HorizontalPager、AnimatedPage 和 ScreenScaffold。
使用 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 } } } } } }
如需完整的實作範例,請參閱 android/snippets 存放區中的 Pager.kt,以及 AndroidX 存放區中的 PagerScaffoldSample.kt。