Làm quen với thẻ thông tin


Để bắt đầu cung cấp thẻ thông tin từ ứng dụng, hãy đưa các phần phụ thuộc sau đây vào tệp build.gradle của ứng dụng.

Groovy

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

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

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

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

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

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

Kotlin

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

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

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

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

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

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

Khái niệm chính

Thẻ thông tin không được xây dựng theo cách giống như ứng dụng Android và sử dụng các khái niệm khác:

  • Mẫu bố cục: Xác định cách sắp xếp tổng thể các thành phần hình ảnh trên màn hình. Bạn có thể thực hiện việc này bằng hàm primaryLayout().
  • Phần tử bố cục: Đại diện cho một phần tử đồ hoạ riêng lẻ, chẳng hạn như nút hoặc thẻ, hoặc một số phần tử như vậy được nhóm lại với nhau bằng cách sử dụng cột, buttonGroup hoặc tương tự. Các thành phần này được nhúng trong một mẫu bố cục.
  • Tài nguyên: Đối tượng ResourceBuilders.Resources bao gồm một bản đồ gồm các cặp khoá-giá trị của tài nguyên Android (hình ảnh) cần thiết để kết xuất bố cục và một phiên bản.
  • Dòng thời gian: Đối tượng TimelineBuilders.Timeline là danh sách một hoặc nhiều thực thể của đối tượng bố cục. Bạn có thể cung cấp nhiều cơ chế và biểu thức để cho biết thời điểm trình kết xuất nên chuyển từ đối tượng bố cục này sang đối tượng bố cục khác, chẳng hạn như ngừng hiển thị bố cục tại một thời điểm cụ thể.
  • Trạng thái: Cấu trúc dữ liệu thuộc loại StateBuilders.State được truyền giữa thẻ thông tin và ứng dụng, để cho phép hai thành phần giao tiếp với nhau. Ví dụ: nếu người dùng nhấn vào một nút trên thẻ thông tin, thì trạng thái sẽ giữ mã nhận dạng của nút đó. Bạn cũng có thể trao đổi các loại dữ liệu bằng cách sử dụng bản đồ.
  • Thẻ thông tin: Đối tượng TileBuilders.Tile đại diện cho một thẻ thông tin, bao gồm dòng thời gian, mã phiên bản tài nguyên, khoảng thời gian làm mới và trạng thái.
  • Protolayout: Thuật ngữ này xuất hiện trong tên của nhiều lớp liên quan đến thẻ thông tin và đề cập đến thư viện Protolayout của Wear OS, một thư viện đồ hoạ được dùng trên nhiều nền tảng Wear OS.

Tạo ô

Sử dụng Material3TileService (nên dùng)

Khi tạo thẻ thông tin Material 3 (androidx.wear.tiles:tiles:1.6.0 trở lên), hãy luôn mở rộng Material3TileService thay vì lớp TileService cấp thấp hơn. Material3TileService cung cấp một cấu trúc ưu tiên Kotlin, có tính định hướng, giúp đơn giản hoá việc phát triển thẻ thông tin:

  • Coroutine Kotlin tích hợp sẵn: Triển khai một hàm tạm ngưng MaterialScope.tileResponse(requestParams: TileRequest): Tile duy nhất thay vì sử dụng ListenableFuture và ghi đè onTileRequest().
  • MaterialScope được định cấu hình sẵn: tileResponse() chạy với MaterialScope làm trình nhận (được định cấu hình thông qua các tham số hàm khởi tạo như allowDynamicTheme và defaultColorScheme), vì vậy, bạn không cần gói bố cục của mình trong lệnh gọi materialScope() dư thừa.
  • Đăng ký tài nguyên một lệnh gọi: Bao gồm ProtoLayoutScope để tự động đăng ký tài nguyên hình ảnh cùng dòng và trả về cả bố cục thẻ thông tin và tài nguyên trong một lệnh gọi liên kết hệ thống. Vì Material3TileService tự động xử lý tài nguyên (final onTileResourcesRequest()), nên đừng ghi đè onTileResourcesRequest().
class MyTileService : Material3TileService() {

    override suspend fun MaterialScope.tileResponse(requestParams: TileRequest): Tile =
        tile(
            timeline =
            Timeline.fromLayoutElement(
                primaryLayout(
                    mainSlot = {
                        text("Hello, World!".layoutString, typography = BODY_LARGE)
                    }
                )
            )
        )
}

Cấu trúc TileService cơ bản

Material3TileService được xây dựng dựa trên lớp TileService cơ sở, mà các ví dụ còn lại trong hướng dẫn này sử dụng để minh hoạ các khái niệm cấp thấp.

Để cung cấp thẻ thông tin từ ứng dụng, hãy triển khai một dịch vụ thuộc loại TileService và đăng ký dịch vụ đó trong tệp kê khai. Từ đó, hệ thống sẽ yêu cầu các thẻ thông tin cần thiết trong các lệnh gọi đến onTileRequest() và các tài nguyên trong các lệnh gọi đến 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())
}

Tiếp theo, hãy thêm một dịch vụ bên trong thẻ <application> của tệp AndroidManifest.xml.

<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>

Bộ lọc quyền và ý định sẽ đăng ký dịch vụ này làm trình cung cấp thẻ thông tin.

Người dùng sẽ thấy biểu tượng, nhãn, nội dung mô tả và tài nguyên xem trước khi định cấu hình thẻ thông tin trên điện thoại hoặc đồng hồ. Xin lưu ý rằng tài nguyên xem trước hỗ trợ tất cả bộ hạn định tài nguyên tiêu chuẩn của Android, vì vậy, bạn có thể thay đổi bản xem trước theo các yếu tố như kích thước màn hình và ngôn ngữ của thiết bị. Hãy xem danh sách kiểm tra bản xem trước để biết thêm các đề xuất.

Triển khai ứng dụng và thêm Thẻ thông tin vào Băng chuyền thẻ thông tin (cũng có một cách thân thiện hơn với nhà phát triển để xem trước Thẻ thông tin, nhưng hiện tại, bạn chỉ cần thực hiện theo cách thủ công).

Một thẻ thông tin Wear OS được tạo bằng Material 3, hiển thị dòng chữ &quot;Hello World&quot;.
Hình 1. Thẻ thông tin "Hello World".

Để xem ví dụ hoàn chỉnh, hãy xem mã mẫu trên GitHub hoặc lớp học lập trình.

Tạo giao diện người dùng cho thẻ thông tin

Các phần tử trên giao diện người dùng biểu cảm của Material 3 Expressive được tạo bằng phương pháp có cấu trúc, dựa trên mẫu trình tạo an toàn về kiểu của Kotlin.

Bố cục

Để biết hướng dẫn về các nguyên tắc thiết kế đằng sau việc tạo bố cục thẻ thông tin hiệu quả và thích ứng, hãy xem phần Bố cục phổ biến cho thẻ thông tin.

Để tạo bố cục, hãy làm như sau:

  1. Bắt đầu phạm vi Material Design: Gọi hàm materialScope(), cung cấp context và deviceConfiguration bắt buộc. Bạn có thể thêm các tham số không bắt buộc, chẳng hạn như allowDynamicTheme và defaultColorScheme. allowDynamicTheme là true theo mặc định và defaultColorScheme đại diện cho ColorScheme được dùng khi không có màu động (chẳng hạn như khi người dùng đã tắt tính năng này) hoặc khi thiết bị không hỗ trợ tính năng này hoặc allowDynamicTheme là false). Khi sử dụng các API ImageResource như backgroundImage() trong TileService tuỳ chỉnh, hãy gọi materialScopeWithResources().

  2. Xây dựng giao diện người dùng trong phạm vi: Tất cả thành phần giao diện người dùng cho một bố cục Thẻ thông tin nhất định phải được xác định trong lambda của một lệnh gọi materialScope() cấp cao nhất. Các hàm thành phần này, chẳng hạn như primaryLayout() và textEdgeButton(), là các hàm mở rộng trên MaterialScope và chỉ có sẵn khi được gọi trên phạm vi nhận này.

    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(
                    labelContent = { text("Action".layoutString) },
                    onClick = clickable()
                )
            }
        )
    }

Máy đánh bạc

Trong M3, bố cục thẻ thông tin sử dụng phương pháp lấy cảm hứng từ Compose, tận dụng 3 vị trí riêng biệt. Từ trên xuống dưới, các thành phần này là:

  1. titleSlot, thường dành cho tiêu đề chính hoặc tiêu đề.
  2. mainSlot, cho nội dung cốt lõi.
  3. bottomSlot, thường được dùng cho các thao tác hoặc thông tin bổ sung. Đây cũng là nơi nút cạnh xuất hiện.
Bố cục thẻ thông tin cho thấy titleSlot, mainSlot và bottomSlot
Hình 2. titleSlot, mainSlot và bottomSlot.

Nội dung của mỗi vị trí như sau:

  • titleSlot (không bắt buộc): Thường là một vài từ do text() tạo ra.
  • mainSlot (bắt buộc): Các thành phần được sắp xếp thành các cấu trúc như hàng, cột và nhóm nút. Các thành phần này cũng có thể được nhúng đệ quy vào nhau; ví dụ: một cột có thể chứa các hàng.
  • bottomSlot (không bắt buộc): Thường được lấp đầy bằng nút ôm sát cạnh hoặc nhãn văn bản.

Vì không thể cuộn thẻ thông tin nên không có thành phần nào để phân trang, cuộn hoặc xử lý danh sách nội dung dài. Hãy đảm bảo nội dung vẫn hiển thị khi cỡ chữ tăng lên hoặc văn bản dài hơn do bản dịch.

Thành phần giao diện người dùng

Thư viện protolayout-material3 cung cấp một số lượng lớn thành phần được thiết kế theo thông số kỹ thuật và đề xuất về giao diện người dùng của Material 3 Expressive.

Nút

Nút chủ yếu hướng đến hành động. Các sự kiện này dùng để kích hoạt những hành động cụ thể. Nội dung của mỗi nút, chẳng hạn như biểu tượng hoặc văn bản ngắn, xác định hành động.

  • textButton(): nút có một khe duy nhất cho nội dung văn bản (ngắn)
  • iconButton(): nút có một khe duy nhất để biểu thị một biểu tượng
  • avatarButton(): nút hình đại diện dạng viên thuốc, cung cấp tối đa 3 vùng để chứa nội dung đại diện cho nhãn và nhãn phụ xếp chồng theo chiều dọc, cùng một hình ảnh (hình đại diện) bên cạnh
  • imageButton(): nút hình ảnh có thể nhấp vào, không cung cấp thêm vùng, chỉ có hình ảnh (ví dụ: backgroundImage làm nền)
  • compactButton(): nút thu gọn cung cấp tối đa hai khe để lấy nội dung xếp chồng theo chiều ngang, đại diện cho một biểu tượng và văn bản bên cạnh biểu tượng đó
  • button(): nút hình viên thuốc cung cấp tối đa 3 vùng để chứa nội dung đại diện cho nhãn và nhãn phụ xếp chồng theo chiều dọc, cùng một biểu tượng bên cạnh

Nút cạnh

Nút ở cạnh là một nút chuyên biệt, có chiều rộng tối đa, được cố định ở cuối màn hình tròn của đồng hồ, thể hiện hành động quan trọng nhất cần thực hiện trên màn hình thẻ thông tin hiện tại.

  • iconEdgeButton(): nút cạnh cung cấp một khe duy nhất để chứa biểu tượng hoặc nội dung nhỏ, tròn tương tự
  • textEdgeButton(): nút cạnh cung cấp một khe duy nhất để lấy văn bản hoặc nội dung dài và rộng tương tự

Thẻ

Thẻ chủ yếu hướng đến thông tin. Các bảng này hiển thị tập hợp dữ liệu có cấu trúc và có liên quan. Mặc dù bạn có thể tạo thẻ tương tác, nhưng các thẻ này thường hiển thị thông tin tóm tắt mà người dùng có thể nhấn vào để xem thêm thông tin chi tiết hoặc thực hiện một hành động liên quan.

  • titleCard(): thẻ tiêu đề cung cấp từ 1 đến 3 vị trí, thường dựa trên văn bản
  • appCard(): thẻ ứng dụng cung cấp tối đa 5 vị trí, thường dựa trên văn bản
  • textDataCard(): thẻ dữ liệu cung cấp tối đa 3 ô xếp chồng theo chiều dọc, thường dựa trên văn bản hoặc chữ số
  • iconDataCard(): thẻ dữ liệu cung cấp tối đa 3 ô xếp chồng theo chiều dọc, thường dựa trên văn bản hoặc chữ số, có biểu tượng
  • graphicDataCard(): thẻ dữ liệu đồ hoạ cung cấp một vùng cho dữ liệu đồ hoạ, chẳng hạn như chỉ báo tiến trình và tối đa hai vùng xếp chồng theo chiều dọc, thường là cho nội dung mô tả bằng văn bản

Chỉ báo tiến trình

  • circularProgressIndicator(): cho biết tiến trình đạt được mục tiêu bằng cách sử dụng phần tử hướng tâm
  • segmentedCircularProgressIndicator(): cho biết tiến trình hướng tới mục tiêu bằng cách sử dụng một phần tử hướng tâm có các giai đoạn riêng biệt

Phần tử của bố cục nhóm

  • buttonGroup(): bố cục thành phần đặt các phần tử con theo trình tự ngang
  • primaryLayout(): bố cục toàn màn hình thể hiện kiểu bố cục M3 được đề xuất, có tính thích ứng và đảm nhiệm việc đặt các phần tử, cùng với lề và khoảng đệm được đề xuất áp dụng

Áp dụng giao diện

Trong Material 3 Expressive, hệ thống màu được xác định bằng 29 vai trò màu tiêu chuẩn, được sắp xếp thành 6 nhóm: màu chính, màu phụ, màu thứ ba, màu lỗi, màu bề mặt và màu đường viền.

Hệ thống màu sắc biểu cảm của Material 3 Expressive, cho thấy các vai trò màu sắc được sắp xếp thành các nhóm như màu chính, màu phụ, màu thứ ba, màu lỗi, màu bề mặt và màu đường viền.
Hình 3. Hệ thống màu biểu cảm Material 3 Expressive.

ColorScheme liên kết từng vai trò trong số 29 vai trò này với một màu tương ứng và vì đây là một phần của MaterialScope nên các thành phần phải được tạo trong đó, chúng sẽ tự động lấy màu từ bảng phối màu. Phương pháp này giúp tất cả phần tử trên giao diện người dùng tự động tuân thủ các tiêu chuẩn của Material Design.

Để cho phép người dùng chọn giữa bảng phối màu mà bạn xác định (chẳng hạn như bảng phối màu phản ánh màu sắc thương hiệu của bạn) và bảng phối màu do hệ thống cung cấp (bắt nguồn từ mặt đồng hồ hiện tại của người dùng hoặc do người dùng chọn), hãy khởi chạy MaterialScope như sau:

val myColorScheme =
    ColorScheme(
        primary = Color.rgb(0, 0, 255).argb, // Blue
        onPrimary = Color.rgb(255, 255, 255).argb, // White
        // 27 more
    )

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

Nếu bạn chọn cách này, hãy cung cấp biểu tượng ô đơn sắc để có thể phủ màu chính xác nhằm mang lại khả năng hiển thị tối ưu trên mọi giao diện.

Để buộc các ô xuất hiện trong bảng phối màu bạn cung cấp, hãy tắt tính năng hỗ trợ giao diện động bằng cách đặt allowDynamicTheme thành false:

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

Màu

Mỗi thành phần riêng lẻ sử dụng một nhóm nhỏ trong số 29 vai trò màu sắc do ColorScheme xác định. Ví dụ: các nút sử dụng tối đa 4 màu, theo mặc định được lấy từ nhóm "chính" của ColorScheme đang hoạt động:

Mã thông báo thành phần ButtonColors Vai trò ColorScheme
containerColor chính
iconColor onPrimary
labelColor onPrimary
secondaryLabelColor onPrimary (độ mờ 0,8)

Để biết hướng dẫn chi tiết về cách áp dụng màu cho thiết kế Wear OS, hãy xem hướng dẫn thiết kế màu.

Bạn có thể cần phải điều chỉnh mã hiệu màu mặc định cho các phần tử giao diện người dùng cụ thể. Ví dụ: bạn có thể muốn một textEdgeButton sử dụng màu từ nhóm "phụ" hoặc "bậc ba" thay vì "chính" để nổi bật và có độ tương phản tốt hơn.

Bạn có thể tuỳ chỉnh màu của thành phần theo một số cách:

  1. Sử dụng hàm trợ giúp cho các màu được xác định trước. Sử dụng các hàm trợ giúp như filledTonalButtonColors() để áp dụng kiểu nút tiêu chuẩn cho Material 3 Expressive. Các hàm này tạo các thực thể ButtonColors được định cấu hình sẵn, liên kết các kiểu phổ biến như được tô màu, có sắc độ hoặc có đường viền với các vai trò thích hợp từ ColorScheme đang hoạt động trong MaterialScope. Điều này cho phép bạn áp dụng các kiểu nhất quán mà không cần xác định từng màu cho các loại nút phổ biến theo cách thủ công.

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

    Đối với thẻ, hãy sử dụng nhóm hàm filledCardColors() tương đương.

    Bạn cũng có thể sửa đổi đối tượng ButtonColors do các hàm trợ giúp trả về bằng phương thức copy() nếu chỉ cần thay đổi một hoặc hai mã thông báo:

    textEdgeButton(
        colors =
        filledButtonColors()
            .copy(
                containerColor = colorScheme.tertiary,
                labelColor = colorScheme.onTertiary
            ),
        // ... other parameters
    )

  2. Cung cấp rõ ràng các vai trò màu thay thế. Tạo đối tượng ButtonColors của riêng bạn rồi truyền đối tượng đó đến thành phần. Đối với thẻ, hãy sử dụng đối tượng CardColors tương đương.

    textEdgeButton(
        colors =
        ButtonColors(
            // the materialScope makes colorScheme available
            containerColor = colorScheme.secondary,
            iconColor = colorScheme.secondaryDim,
            labelColor = colorScheme.onSecondary,
            secondaryLabelColor = colorScheme.onSecondary
        ),
        // ... other parameters
    )

  3. Chỉ định màu cố định (hãy thận trọng khi sử dụng). Mặc dù bạn nên chỉ định màu theo vai trò ngữ nghĩa (ví dụ: colorScheme.primary), nhưng bạn cũng có thể cung cấp trực tiếp các giá trị màu. Bạn nên hạn chế sử dụng phương pháp này vì có thể dẫn đến sự không nhất quán với giao diện tổng thể, đặc biệt là nếu giao diện thay đổi linh động.

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

Kiểu chữ

Để biết thêm thông tin về cách sử dụng kiểu chữ hiệu quả trong thiết kế, hãy xem hướng dẫn thiết kế kiểu chữ.

Để tạo sự nhất quán về hình ảnh trên nền tảng Wear OS và tối ưu hoá hiệu suất, tất cả văn bản trên thẻ thông tin đều được kết xuất bằng phông chữ do hệ thống cung cấp. Tức là thẻ thông tin không hỗ trợ kiểu chữ tuỳ chỉnh. Trên Wear OS 6 trở lên, đây là phông chữ dành riêng cho OEM. Trong hầu hết các trường hợp, đây sẽ là phông chữ biến đổi, mang lại trải nghiệm biểu cảm hơn và khả năng kiểm soát chi tiết hơn.

Để tạo kiểu văn bản, bạn thường sử dụng phương thức text() kết hợp với hằng số kiểu chữ. Thành phần này cho phép bạn sử dụng các vai trò kiểu chữ được xác định trước trong Material 3 Expressive, giúp thẻ thông tin của bạn tuân thủ các phương pháp hay nhất về kiểu chữ để đảm bảo khả năng đọc và phân cấp. Thư viện này cung cấp một bộ gồm 18 hằng số kiểu chữ ngữ nghĩa, chẳng hạn như BODY_MEDIUM. Các hằng số này cũng ảnh hưởng đến các trục phông chữ khác ngoài kích thước.

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

Để có thêm quyền kiểm soát, bạn có thể cung cấp thêm chế độ cài đặt. Trên Wear OS 6 trở lên, có thể bạn sẽ sử dụng phông chữ biến thiên. Bạn có thể sửa đổi phông chữ này theo các trục italic (nghiêng), weight (độ đậm), width (chiều rộng) và roundness (độ tròn). Bạn có thể kiểm soát các trục này bằng cách sử dụng tham số 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)
    ),
)

Cuối cùng, nếu bạn cần kiểm soát kích thước hoặc khoảng cách giữa các chữ cái (không nên dùng), hãy sử dụng basicText() thay vì text() và tạo một giá trị cho thuộc tính fontStyle bằng fontStyle()).

Hình dạng và lề

Bạn có thể thay đổi bán kính góc của hầu hết mọi thành phần bằng thuộc tính shape của thành phần đó. Giá trị lấy từ thuộc tính MaterialScope shapes:

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

Sau khi thay đổi hình dạng của một thành phần, nếu bạn cho rằng thành phần đó để lại quá nhiều hoặc quá ít không gian xung quanh cạnh của màn hình, hãy điều chỉnh lề bằng cách sử dụng tham số margin của primaryLayout():

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

Vòng cung

Dưới đây là các vùng chứa con Arc được hỗ trợ:

  • ArcLine: hiển thị một đường cong xung quanh Vòng cung.
  • ArcText: hiển thị văn bản cong trong Vòng cung.
  • ArcAdapter: hiển thị một phần tử bố cục cơ bản trong vòng cung, được vẽ tại tiếp tuyến của vòng cung.

Để biết thêm thông tin, hãy xem tài liệu tham khảo cho từng loại phần tử.

Đối tượng sửa đổi

Bạn có thể tuỳ ý áp dụng các công cụ sửa đổi cho mỗi phần tử bố cục có sẵn. Hãy sử dụng các công cụ sửa đổi này cho những mục đích sau:

  • Thay đổi giao diện hình ảnh của bố cục. Ví dụ: thêm nền, đường viền hoặc khoảng đệm vào phần tử bố cục.
  • Thêm siêu dữ liệu về bố cục. Ví dụ: thêm một đối tượng sửa đổi ngữ nghĩa vào phần tử bố cục để sử dụng với trình đọc màn hình.
  • Thêm chức năng. Ví dụ: thêm vào phần tử bố cục một đối tượng sửa đổi có thể nhấp để thẻ thông tin có khả năng tương tác. Để biết thêm thông tin, hãy xem bài viết Tương tác với thẻ thông tin.

Ví dụ: chúng ta có thể tuỳ chỉnh giao diện và siêu dữ liệu mặc định của Image, như trong mã mẫu sau:

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

Spannable

Spannable là loại vùng chứa đặc biệt có nhiệm vụ sắp xếp các phần tử tương tự như văn bản. Vùng chứa này hữu ích khi bạn muốn áp dụng kiểu khác cho duy nhất một chuỗi con trong khối văn bản lớn hơn – đây là điều không thể áp dụng với phần tử Text.

Vùng chứa Spannable chứa phần tử con Span. Bạn không được phép dùng các phần tử con khác hoặc các thực thể Spannable lồng nhau.

Có hai loại phần tử con Span:

  • SpanText: hiển thị văn bản có một kiểu cụ thể.
  • SpanImage: hiển thị hình ảnh cùng dòng với văn bản.

Ví dụ: bạn có thể in nghiêng từ "world" (mọi người) trong thẻ thông tin "Hello world" (Chào mọi người) và chèn một hình ảnh giữa các từ, như trong mã mẫu sau đây:

private fun mySpannable(): LayoutElement =
    LayoutElementBuilders.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()

Làm việc với các tài nguyên

Ô không có quyền truy cập vào bất kỳ tài nguyên nào trong ứng dụng của bạn. Điều này có nghĩa là bạn không thể chuyển mã nhận dạng hình ảnh Android vào phần tử bố cục Image và kỳ vọng nó sẽ thực hiện phân giải. Thay vào đó, hãy ghi đè phương thức onTileResourcesRequest() và cung cấp mọi tài nguyên theo cách thủ công.

Có 2 cách để cung cấp hình ảnh trong phương thức onTileResourcesRequest():

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

Danh sách kiểm tra hình ảnh xem trước của ô

Hệ thống sẽ hiển thị hình ảnh xem trước của thẻ thông tin (được tham chiếu trong tệp kê khai ứng dụng Android) trong trình chỉnh sửa băng chuyền thẻ thông tin để thêm thẻ thông tin mới. Trình chỉnh sửa này xuất hiện trên cả thiết bị Wear OS và trong ứng dụng đồng hành của đồng hồ trên điện thoại.

Để giúp người dùng tận dụng tối đa hình ảnh xem trước này, hãy xác minh các thông tin chi tiết sau về thẻ thông tin của bạn:

  • Phản ánh thiết kế mới nhất. Bản xem trước phải thể hiện chính xác thiết kế mới nhất của thẻ thông tin.
  • Sử dụng kích thước được đề xuất. Để mang lại chất lượng hiển thị tốt nhất có thể và trải nghiệm tốt cho người dùng, hình ảnh xem trước phải có kích thước 400 px x 400 px.
  • Sử dụng chủ đề màu sắc tĩnh. Sử dụng chủ đề màu sắc tĩnh của thẻ thông tin, không phải chủ đề màu sắc động.
  • Bao gồm biểu tượng ứng dụng. Xác nhận rằng biểu tượng của ứng dụng xuất hiện ở đầu hình ảnh xem trước.
  • Cho biết trạng thái đã tải/đã đăng nhập. Bản xem trước phải hiển thị trạng thái "đã tải" hoặc "đã đăng nhập" đầy đủ chức năng, tránh mọi nội dung trống hoặc nội dung giữ chỗ.
  • Tận dụng các quy tắc phân giải tài nguyên để tuỳ chỉnh (không bắt buộc). Cân nhắc sử dụng quy tắc phân giải tài nguyên của Android để cung cấp bản xem trước phù hợp với kích thước màn hình, ngôn ngữ hoặc chế độ cài đặt ngôn ngữ của thiết bị. Điều này đặc biệt hữu ích nếu giao diện của thẻ thông tin khác nhau giữa các thiết bị.