開始使用資訊方塊


如果想為應用程式提供資訊方塊,請把下列依附元件加入應用程式的 build.gradle 檔案內。

Groovy

dependencies {
    // Use to implement support for wear tiles
    implementation "androidx.wear.tiles:tiles:1.4.1"

    // Use to utilize standard components and layouts in your tiles
    implementation "androidx.wear.protolayout:protolayout:1.2.1"

    // Use to utilize components and layouts with Material Design in your tiles
    implementation "androidx.wear.protolayout:protolayout-material:1.2.1"

    // Use to include dynamic expressions in your tiles
    implementation "androidx.wear.protolayout:protolayout-expression:1.2.1"

    // Use to preview wear tiles in your own app
    debugImplementation "androidx.wear.tiles:tiles-renderer:1.4.1"

    // Use to fetch tiles from a tile provider in your tests
    testImplementation "androidx.wear.tiles:tiles-testing:1.4.1"
}

Kotlin

dependencies {
    // Use to implement support for wear tiles
    implementation("androidx.wear.tiles:tiles:1.4.1")

    // Use to utilize standard components and layouts in your tiles
    implementation("androidx.wear.protolayout:protolayout:1.2.1")

    // Use to utilize components and layouts with Material Design in your tiles
    implementation("androidx.wear.protolayout:protolayout-material:1.2.1")

    // Use to include dynamic expressions in your tiles
    implementation("androidx.wear.protolayout:protolayout-expression:1.2.1")

    // Use to preview wear tiles in your own app
    debugImplementation("androidx.wear.tiles:tiles-renderer:1.4.1")

    // Use to fetch tiles from a tile provider in your tests
    testImplementation("androidx.wear.tiles:tiles-testing:1.4.1")
}

核心概念

資訊方塊的建構方式與 Android 應用程式不同,且採用不同的概念:

  • 版面配置範本:定義螢幕上視覺元素的整體排列方式。這項操作是由 primaryLayout() 函式完成。
  • 版面配置元素:代表個別圖形元素,例如按鈕資訊卡,或是使用buttonGroup 或類似項目將多個這類元素分組。這些元素會嵌入版面配置範本中。
  • 資源: ResourceBuilders.Resources 物件包含一個地圖,其中包含繪製版面配置所需的 Android 資源 (圖片) 鍵/值組合,以及版本
  • 時間軸:TimelineBuilders.Timeline 物件是一或多個版面配置物件的清單。您可以提供各種機制和運算式,指出轉譯器應在何時從一個版面配置物件切換至另一個版面配置物件,例如在特定時間停止顯示版面配置。
  • 狀態:在資訊方塊和應用程式之間傳遞的 StateBuilders.State 類型資料結構,可讓這兩個元件相互通訊。舉例來說,如果使用者輕觸資訊方塊上的按鈕,狀態會保留按鈕的 ID。您也可以使用對應表來交換資料類型。
  • 圖塊:代表圖塊的 TileBuilders.Tile 物件,包含時間表資源版本 ID新鮮度間隔狀態
  • Protolayout:這個字詞會出現在各種圖塊相關類別的名稱中,並指的是 Wear OS Protolayout 程式庫,這是在各種 Wear OS 途徑中使用的圖形程式庫。

建立資訊方塊

如要從應用程式提供資訊方塊,請實作 TileService 類型的服務,並在資訊清單中註冊該服務。因此,系統會在呼叫 onTileRequest() 時要求必要的圖塊,並在呼叫 onTileResourcesRequest() 時要求資源

class MyTileService : TileService() {

    override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
        Futures.immediateFuture(
            Tile.Builder()
                .setResourcesVersion(RESOURCES_VERSION)
                .setTileTimeline(
                    Timeline.fromLayoutElement(
                        materialScope(this, requestParams.deviceConfiguration) {
                            primaryLayout(
                                mainSlot = {
                                    text("Hello, World!".layoutString, typography = BODY_LARGE)
                                }
                            )
                        }
                    )
                )
                .build()
        )

    override fun onTileResourcesRequest(requestParams: ResourcesRequest) =
        Futures.immediateFuture(
            Resources.Builder().setVersion(RESOURCES_VERSION).build()
        )
}

接下來,請在 AndroidManifest.xml 檔案的 <application> 標記內新增服務。

<service
    android:name=".snippets.m3.tile.MyTileService"
    android:label="@string/tile_label"
    android:description="@string/tile_description"
    android:icon="@mipmap/ic_launcher"
    android:exported="true"
    android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
    <intent-filter>
        <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
    </intent-filter>

    <meta-data android:name="androidx.wear.tiles.PREVIEW"
        android:resource="@drawable/tile_preview" />
</service>

權限和意圖篩選器會將此服務註冊為資訊方塊提供者。

當使用者透過手機或手錶設定資訊方塊時,可看到圖示、標籤、說明和預覽資源。請注意,預覽資源支援所有 Android 的標準資源限定詞,因此可以根據螢幕大小和裝置語言等因素變更預覽畫面。如需其他最佳化建議,請參閱預覽檢查清單

部署應用程式,然後將資訊方塊新增至資訊方塊輪轉介面 (開發人員還有其他更方便的資訊方塊預覽方式,但目前請先手動操作)。

「Hello World」資訊方塊。
圖 1. 「Hello World」資訊方塊。

如需完整範例,請參閱 GitHub 上的程式碼範例程式碼研究室

建立資訊方塊 UI

Material 3 表情符號 UI 元素是使用結構化方法建立,並由 Kotlin 的型別安全建構工具模式提供支援。

版面配置

如要建立版面配置,請按照下列步驟操作:

  1. 啟動 Material Design 範圍:呼叫 materialScope() 函式,提供必要的 contextdeviceConfiguration。您可以加入選用參數,例如 allowDynamicThemedefaultColorSchemeallowDynamicTheme 預設為 truedefaultColorScheme 則代表在無法使用動態色彩 (例如使用者已關閉這項功能) 或裝置不支援這項功能 (或 allowDynamicThemefalse) 時使用的 ColorScheme

  2. 在範圍內建構 UI:特定方塊版面配置的所有 UI 元件,都必須在單一頂層 materialScope() 呼叫的 lambda 中定義。這些元件函式 (例如 primaryLayout()textEdgeButton()) 是 MaterialScope 的擴充函式,且只能在接收器範圍中呼叫。

    materialScope(
        context = context,
        deviceConfiguration = requestParams.deviceConfiguration, // requestParams is passed to onTileRequest
        defaultColorScheme = myFallbackColorScheme
    ) {
        // inside the MaterialScope, you can call functions like primaryLayout()
        primaryLayout(
            titleSlot = { text(text = "Title".layoutString) },
            mainSlot = { text(text = "Main Content".layoutString) },
            bottomSlot = { textEdgeButton(text = "Action".layoutString) }
        )
    }
    

吃角子老虎

在 M3 中,圖塊版面配置採用 Compose 的做法,使用三個不同的插槽。由上而下分別為:

  1. titleSlot,通常用於主要標題或標題行。
  2. mainSlot:用於核心內容。
  3. bottomSlot 通常用於動作或補充資訊。這也是邊緣按鈕顯示的位置。
顯示標題區塊、主區塊和底部區塊的圖塊版面配置
圖 2. titleSlot、mainSlot 和 bottomSlot。

每個版位的內容如下:

  • titleSlot (選用):通常是 text() 產生的幾個字。
  • mainSlot (必要):元件會以按鈕群組等結構組織起來。這些元件也可以遞迴嵌入彼此中,例如資料欄可以包含資料列。
  • bottomSlot (選用):通常會填入邊緣貼合按鈕或文字標籤。

由於方塊無法捲動,因此沒有用於分頁、捲動或處理長內容清單的元件。請注意,當字型大小增加或文字因翻譯而變長時,內容仍能正常顯示。

UI 元件

protolayout-material3 程式庫提供大量元件,這些元件均根據 Material 3 Expressive 規格和使用者介面建議事項設計。

按鈕

  • textButton():按鈕,其中包含一個用於 (簡短) 文字內容的單一版位
  • iconButton():按鈕,其中包含一個用來代表圖示的版位
  • avatarButton():圓形顯示圖片按鈕,最多提供三個方塊,用於顯示代表垂直堆疊標籤和次要標籤的內容,以及旁邊的圖片 (顯示圖片)
  • imageButton():可點選的圖片按鈕,不提供額外空格,僅提供圖片 (例如 backgroundImage 做為背景)
  • compactButton():精簡按鈕,最多提供兩個版位,可用於水平堆疊的內容,代表圖示和文字
  • button():圓形按鈕,最多提供三個版位,可用於顯示代表垂直堆疊標籤和次要標籤的內容,以及旁邊的圖示

邊緣按鈕

  • iconEdgeButton():邊緣按鈕,提供單一版位,可擷取圖示或類似圓形的小型內容
  • textEdgeButton():邊緣按鈕,提供單一版位,可擷取文字或類似的長寬內容

資訊卡

  • titleCard():提供一到三個插槽的標題卡,通常是文字格式
  • appCard():最多提供五個插槽的應用程式資訊卡,通常以文字為主
  • textDataCard():資訊卡最多可提供三個垂直堆疊的空格,通常以文字或數字為基礎
  • iconDataCard():資料卡片,最多可提供三個垂直堆疊的插槽,通常以文字或數字為基礎,並附有圖示
  • graphicDataCard():圖形資料卡,提供圖形資料的資料欄,例如進度指示器,以及最多兩個垂直堆疊的資料欄,通常用於文字說明

進度指標

將版面配置元素分組

  • buttonGroup():將子項以水平序列排列的元件版面配置
  • primaryLayout():全螢幕版面配置,代表建議的 M3 版面配置樣式,可回應並處理元素的放置方式,以及套用的建議邊界和邊框

主題設定

在 Material 3 Expressive 中,色彩系統是由 29 個標準顏色角色定義,並分為六個群組:主要、次要、第三要、錯誤、表面和外框。

Material 3 表情符號色彩系統
圖 3. Material 3 表情符號色彩系統。

ColorScheme 會將這 29 個角色逐一對應至對應的顏色,且由於它是 MaterialScope 的一部分,且元件必須在其中建立,因此會自動採用色彩配置中的顏色。這種做法可讓所有 UI 元素自動遵循 Material Design 標準。

如要讓使用者選擇您定義的色彩配置 (例如反映品牌顏色的色彩配置),以及系統提供的色彩配置 (取決於使用者目前的錶面,或使用者選擇的錶面),請按照下列方式初始化 MaterialScope

val myColorScheme =
    ColorScheme(
        primary = ...
        onPrimary = ...
        // 27 more
    )

materialScope(
  defaultColorScheme = myColorScheme
) {
  // If the user selects "no theme" in settings, myColorScheme is used.
  // Otherwise, the system-provided theme is used.
}

如要強制讓方塊顯示在您提供的色彩配置中,請將 allowDynamicTheme 設為 false,停用動態主題設定功能:

materialScope(
  allowDynamicTheme = false,
  defaultColorScheme = myColorScheme
) {
  // myColorScheme is *always* used.
}

顏色

每個個別元件都會使用 ColorScheme 定義的 29 個顏色角色中的子集。舉例來說,按鈕最多可使用四種顏色,這些顏色預設會從有效 ColorScheme 的「primary」群組取得:

ButtonColors 元件權杖 ColorScheme 角色
containerColor primary
iconColor onPrimary
labelColor onPrimary
secondaryLabelColor onPrimary (透明度 0.8)

您可能需要為特定 UI 元素使用與預設顏色符記不同的顏色。舉例來說,您可能會希望一個 textEdgeButton 使用「次要」或「三次要」群組的顏色,而非「主要」群組,以便突顯並提供更佳的對比度。

您可以透過下列幾種方式自訂元件顏色:

  1. 使用預先定義顏色的輔助函式。使用 filledTonalButtonColors() 等輔助函式,為 Material 3 Expressive 套用標準按鈕樣式。這些函式會建立預先設定的 ButtonColors 例項,將填滿、色調或輪廓等常見樣式對應至 MaterialScope 中有效 ColorScheme 的適當角色。這樣一來,您就能套用一致的樣式,而無須為常見的按鈕類型手動定義每種顏色。

    textEdgeButton(
        colors = filledButtonColors() // default
        /* OR colors = filledTonalButtonColors() */
        /* OR colors = filledVariantButtonColors() */
        // ... other parameters
    )
    

    如為資訊卡,請使用等效的 filledCardColors() 系列函式。

    如果您只需要變更一或兩個符記,也可以使用輔助函式的 copy() 方法修改輔助函式傳回的 ButtonColors 物件:

    textEdgeButton(
        colors =
            filledButtonColors()
                .copy(
                    containerColor = colorScheme.tertiary,
                    labelColor = colorScheme.onTertiary
                )
        // ... other parameters
    )
    
  2. 明確提供替換顏色角色。建立自己的 ButtonColors 物件,並將其傳遞至元件。如為資訊卡,請使用相等的 CardColors 物件。

    textEdgeButton(
        colors =
            ButtonColors(
                // the materialScope makes colorScheme available
                containerColor = colorScheme.secondary,
                iconColor = colorScheme.secondaryDim,
                labelColor = colorScheme.onSecondary,
                secondaryLabelColor = colorScheme.onSecondary
            )
        // ... other parameters
    )
    
  3. 指定固定顏色 (請謹慎使用)。雖然一般建議您根據語意角色 (例如colorScheme.primary),您也可以直接提供顏色值。請盡量避免使用這種做法,因為這可能會導致整體主題不一致,尤其是主題會動態變更時。

    textEdgeButton(
        colors = filledButtonColors().copy(
            containerColor = android.graphics.Color.RED.argb, // Using named colors
            labelColor = 0xFFFFFF00.argb // Using a hex code for yellow
        )
        // ... other parameters
    )
    

字體排版

為在 Wear OS 平台上建立一致的視覺效果,並提升效能,方塊上的所有文字都會使用系統提供的字型轉譯。也就是說,資訊方塊不支援自訂字型。在 Wear OS 6 以上版本中,這是 OEM 專屬字型。在多數情況下,這會是可變字型,可提供更具表達力的體驗和更精細的控管功能。

如要建立文字樣式,通常會使用 text() 方法搭配排版常數。這個元件可讓您在 Material 3 Expressive 中使用預先定義的字體排版角色,協助資訊方塊遵循已建立的字體排版最佳做法,以便確保可讀性和階層。這個程式庫提供一組 18 個語義字體排版常數,例如 BODY_MEDIUM。這些常數也會影響字型大小以外的軸。

text(
    text = "Hello, World!".layoutString,
    typography = BODY_MEDIUM,
)

如要進一步控管,您可以提供其他設定。在 Wear OS 6 以上版本中,系統可能會使用可變字型,您可以沿著軸線修改 斜體粗細寬度圓滑度。您可以使用 settings 參數控制這些軸:

text(
    text = "Hello, World".layoutString,
    italic = true,

    // Use elements defined in androidx.wear.protolayout.LayoutElementBuilders.FontSetting
    settings =
        listOf(weight(500), width(100F), roundness(100)),
)

最後,如果您需要控制大小字母間距 (不建議使用),請使用 basicText() 而非 text(),並使用 fontStyle()fontStyle 屬性建構值。

形狀和邊界

您可以使用幾乎所有元件的 shape 屬性變更其圓角半徑。值來自 MaterialScope 屬性 shapes

textButton(
   height = expand(),
   width = expand(),
   shape = shapes.medium, // OR another value like shapes.full
   colors = filledVariantButtonColors(),
   labelContent = { text("Hello, World!".layoutString) },
)

變更元件形狀後,如果您認為元件在螢幕邊緣周圍留有太多或太少空間,請使用 primaryLayout()margin 參數調整邊界:

primaryLayout(
    mainSlot = {
        textButton(
            shape = shapes.small,
            /* ... */
        )
    },
    // margin constants defined in androidx.wear.protolayout.material3.PrimaryLayoutMargins
    margins = MAX_PRIMARY_LAYOUT_MARGIN,
)

弧形

系統支援以下 Arc 容器子項:

  • ArcLine:在弧形周遭轉譯曲線。
  • ArcText:在弧形內轉譯弧形文字。
  • ArcAdapter:在弧形內轉譯基礎版面配置元素,然後在弧形的切線上繪製。

如要進一步瞭解每種元素類型,請參閱參考文件

修飾符

每種可用版面配置元素都可以選擇套用修飾符。以下為修飾符的使用目的:

  • 變更版面配置外觀,例如為版面配置元素新增背景、框線或邊框間距。
  • 新增版面配置的中繼資料,例如為版面配置元素新增語意修飾符,與螢幕閱讀器搭配使用。
  • 新增功能,例如為版面配置元素新增可供點選的修飾符,讓使用者與資訊方塊互動。詳情請參閱「與資訊方塊互動」一文。

舉例來說,我們可以自訂 Image 的預設外觀和中繼資料,如以下程式碼範例所示:

Kotlin

private fun myImage(): LayoutElement =
    Image.Builder()
        .setWidth(dp(24f))
        .setHeight(dp(24f))
        .setResourceId("image_id")
        .setModifiers(Modifiers.Builder()
            .setBackground(Background.Builder().setColor(argb(0xFFFF0000)).build())
            .setPadding(Padding.Builder().setStart(dp(12f)).build())
            .setSemantics(Semantics.builder()
                .setContentDescription("Image description")
                .build()
            ).build()
        ).build()

Java

private LayoutElement myImage() {
   return new Image.Builder()
           .setWidth(dp(24f))
           .setHeight(dp(24f))
           .setResourceId("image_id")
           .setModifiers(new Modifiers.Builder()
                   .setBackground(new Background.Builder().setColor(argb(0xFFFF0000)).build())
                   .setPadding(new Padding.Builder().setStart(dp(12f)).build())
                   .setSemantics(new Semantics.Builder()
                           .setContentDescription("Image description")
                           .build()
                   ).build()
           ).build();
}

Spannable

Spannable 是特殊類型的容器,可以使用和文字類似的方式排列元素。如果您想為大型文字區塊中的單一子字串套用其他樣式,而 Text 元素無法達到這個效果,就適合使用這種容器。

Spannable 容器會由 Span 子項填滿,不得使用其他子項或巢狀 Spannable 例項。

Span 子項分為兩種類型:

  • SpanText:以特定樣式轉譯文字。
  • SpanImage:算繪內嵌文字的圖片。

舉例來說,您可以把「Hello World」資訊方塊內的「world」設為斜體,並在文字間插入圖片,如以下程式碼範例所示:

Kotlin

private fun mySpannable(): LayoutElement =
    Spannable.Builder()
        .addSpan(SpanText.Builder()
            .setText("Hello ")
            .build()
        )
        .addSpan(SpanImage.Builder()
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .setResourceId("image_id")
            .build()
        )
        .addSpan(SpanText.Builder()
            .setText("world")
            .setFontStyle(FontStyle.Builder()
                .setItalic(true)
                .build())
            .build()
        ).build()

Java

private LayoutElement mySpannable() {
   return new Spannable.Builder()
        .addSpan(new SpanText.Builder()
            .setText("Hello ")
            .build()
        )
        .addSpan(new SpanImage.Builder()
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .setResourceId("image_id")
            .build()
        )
        .addSpan(new SpanText.Builder()
            .setText("world")
            .setFontStyle(newFontStyle.Builder()
                .setItalic(true)
                .build())
            .build()
        ).build();
}

使用資源

資訊方塊無法存取應用程式的任何資源。也就是說,您無法將 Android 圖片 ID 傳遞至 Image 版面配置元素,並期望可藉此解決問題。請改為覆寫 onTileResourcesRequest() 方法,並手動提供所有資源。

您可以透過以下兩種方式在 onTileResourcesRequest() 方法中提供圖片:

Kotlin

override fun onTileResourcesRequest(
    requestParams: ResourcesRequest
) = Futures.immediateFuture(
Resources.Builder()
    .setVersion("1")
    .addIdToImageMapping("image_from_resource", ImageResource.Builder()
        .setAndroidResourceByResId(AndroidImageResourceByResId.Builder()
            .setResourceId(R.drawable.image_id)
            .build()
        ).build()
    )
    .addIdToImageMapping("image_inline", ImageResource.Builder()
        .setInlineResource(InlineImageResource.Builder()
            .setData(imageAsByteArray)
            .setWidthPx(48)
            .setHeightPx(48)
            .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565)
            .build()
        ).build()
    ).build()
)

Java

@Override
protected ListenableFuture<Resources> onTileResourcesRequest(
       @NonNull ResourcesRequest requestParams
) {
return Futures.immediateFuture(
    new Resources.Builder()
        .setVersion("1")
        .addIdToImageMapping("image_from_resource", new ImageResource.Builder()
            .setAndroidResourceByResId(new AndroidImageResourceByResId.Builder()
                .setResourceId(R.drawable.image_id)
                .build()
            ).build()
        )
        .addIdToImageMapping("image_inline", new ImageResource.Builder()
            .setInlineResource(new InlineImageResource.Builder()
                .setData(imageAsByteArray)
                .setWidthPx(48)
                .setHeightPx(48)
                .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565)
                .build()
            ).build()
        ).build()
);
}

資訊方塊預覽圖片檢查清單

系統會在資訊方塊輪轉介面編輯器中,顯示 Android 應用程式資訊清單中參照的資訊方塊預覽圖片。這個編輯器會顯示在 Wear OS 裝置和手機上的手錶隨附應用程式中。

為協助使用者充分利用此預覽圖片,請確認資訊方塊的下列詳細資料:

  • 反映最新設計。預覽畫面應準確顯示資訊方塊的最新設計。
  • 使用靜態色彩主題。使用方塊的靜態色彩主題,而非動態主題。
  • 包含應用程式圖示。確認應用程式圖示會顯示在預覽圖片的頂端。
  • 顯示已載入/登入狀態。預覽畫面應顯示功能完整的「已載入」或「已登入」狀態,避免顯示空白或預留位置內容。
  • 利用資源解析規則進行自訂 (選用)。建議您使用 Android 的資源解析度規則,提供符合裝置顯示大小、語言或語言代碼設定的預覽畫面。如果資訊方塊在不同裝置上的外觀不同,這項功能就特別實用。