Compose for Wear OS 的清單功能


使用者可透過清單功能,從 Wear OS 裝置上的一組選項中選取所需項目。

由於許多 Wear OS 裝置都採用圓形螢幕,導致使用者難以查看螢幕頂端和底部附近的清單項目,因此,Compose for Wear OS 納入了名為 TransformingLazyColumnLazyColumn 類別版本,藉此支援縮放和變形動畫。項目移至邊緣時,會縮小並淡出。

如要套用建議的縮放和捲動效果,請按照下列步驟操作:

  1. 使用 Modifier.transformedHeight,讓 Compose 在項目捲動瀏覽畫面時計算高度變化。
  2. 使用 transformation = SurfaceTransformation(transformationSpec) 套用視覺效果,包括縮小項目內容。
  3. 對於不以 transformation 做為參數的元件 (例如 Text),請使用自訂 TransformationSpec

以下動畫顯示清單元素接近螢幕頂端和底部時,如何縮放及變更形狀:

下列程式碼片段說明如何使用 TransformingLazyColumn 版面配置建立清單,在各種 Wear OS 螢幕尺寸上呈現絕佳內容

程式碼片段也示範如何使用 minimumVerticalContentPadding 修飾符,您應在清單項目上設定這個修飾符,以便在清單頂端和底部套用正確的邊框間距。

如要顯示捲動指標,請在 ScreenScaffoldTransformingLazyColumn 之間分享 columnState

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 = "Header")
            }
        }
        // ... other items
        item {
            Button(
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding),
                transformation = SurfaceTransformation(transformationSpec),
                onClick = { /* ... */ },
                icon = {
                    Icon(
                        imageVector = Icons.Default.Build,
                        contentDescription = "build",
                    )
                },
            ) {
                Text(
                    text = "Build",
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
            }
        }
    }
}

新增貼齊與快速滑過效果

「對齊」可確保使用者完成捲動或快速滑動手勢後,清單會停止捲動,且項目會精確地定位在特定位置,通常是螢幕中央。在圓形螢幕上,項目會隨著遠離中心而縮放及變形,因此吸附功能特別實用,可確保最相關的項目在最佳觀看區域中保持完全可見且可讀。

如要新增快速滑動行為,請將 flingBehavior 參數設為 TransformingLazyColumnDefaults.snapFlingBehavior(columnState)。將 rotaryScrollableBehavior 設為相符,並使用 RotaryScrollableDefaults.snapBehavior(columnState),確保使用實體錶冠或錶圈時能獲得一致體驗。

val columnState = rememberTransformingLazyColumnState()
ScreenScaffold(scrollState = columnState) {
    TransformingLazyColumn(
        state = columnState,
        flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState),
        rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(columnState)
    ) {
        // ...
        // ...
    }
}

反向版面配置

根據預設,可捲動的清單會錨定至頂端邊緣。如果使用者捲動至標準清單底部,且清單尾端新增了項目,清單會維持使用者目前檢視的項目。舉例來說,如果使用者正在查看畫面底部的項目 10,且新增了項目 11,則檢視畫面仍會聚焦於項目 10,而項目 11 會顯示在目前檢視畫面下方的畫面外。

對於訊息應用程式或即時記錄等用途,通常不希望出現這種行為。使用者通常希望在清單底部時,能立即看到新項目。如果一次抵達多個項目,清單應略過並在底部顯示最新項目 (也就是說,除非使用者向上捲動,否則可能不會顯示部分中間項目)。

為支援這些用途,TransformingLazyColumn 可讓您設定 reverseLayout = true 來反轉版面配置。這會將清單的錨點從頂端邊緣變更為底部邊緣。

為方便起見,設定 reverseLayout = true 也會反轉項目的視覺順序和捲動手勢的方向:

  • 項目由下往上組成,也就是說,索引 0 會顯示在畫面底部。
  • 向上捲動即可查看指數較高的項目。

如要新增連動和快速滑動行為,並搭配反向版面配置,可以合併 flingBehaviorrotaryScrollableBehavior,如以下程式碼片段所示:

val columnState = rememberTransformingLazyColumnState()
val transformationSpec = rememberTransformationSpec()
ScreenScaffold(scrollState = columnState) { contentPadding ->
    TransformingLazyColumn(
        state = columnState,
        contentPadding = contentPadding,
        reverseLayout = true,
        modifier = Modifier.fillMaxWidth()
    ) {
        items(10) { index ->
            Button(
                label = {
                    Text(
                        text = "Item ${index + 1}"
                    )
                },
                onClick = {},
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding),
                transformation = SurfaceTransformation(transformationSpec)
            )
        }
        item {
            // With reverseLayout = true, the last item declared appears at the top.
            ListHeader(
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding),
                transformation = SurfaceTransformation(transformationSpec)
            ) {
                Text("Header")
            }
        }
    }
}

下圖顯示一般清單和反向清單的差異:

具有一般版面配置的 TransformingLazyColumn,頂端顯示「項目 1」,項目則依遞增順序排列。
圖 1. 標準清單版面配置,內容會從上到下填滿。
具有反向版面配置的 TransformingLazyColumn,底部顯示「項目 1」,項目則由下往上依遞減順序排列。
圖 2. A reversed list layout where content fills from bottom to top.