Bắt đầu sử dụng ô

Stay organized with collections Save and categorize content based on your preferences.

Để bắt đầu cung cấp ô 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.1.0"

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

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

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

Kotlin

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

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

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

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

Tạo ô

Để cung cấp ô từ ứng dụng, hãy tạo một class (lớp) giúp mở rộng TileService và triển khai các phương thức, như trong mã mẫu sau:

Kotlin

private val RESOURCES_VERSION = "1"
class MyTileService : TileService() {
    override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
        Futures.immediateFuture(Tile.Builder()
            .setResourcesVersion(RESOURCES_VERSION)
            .setTimeline(Timeline.Builder().addTimelineEntry(
                TimelineEntry.Builder().setLayout(
                    Layout.Builder().setRoot(
                        Text.Builder().setText("Hello world!").setFontStyle(
                            FontStyle.Builder().setColor(argb(0xFF000000)).build()
                        ).build()
                    ).build()
                ).build()
            ).build()
        ).build())

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

Java

public class MyTileService extends TileService {
    private static final String RESOURCES_VERSION = "1";

    @NonNull
    @Override
    protected ListenableFuture<Tile> onTileRequest(
        @NonNull TileRequest requestParams
    ) {
        return Futures.immediateFuture(new Tile.Builder()
            .setResourcesVersion(RESOURCES_VERSION)
            .setTimeline(new Timeline.Builder()
                .addTimelineEntry(new TimelineEntry.Builder()
                    .setLayout(new Layout.Builder()
                        .setRoot(new Text.Builder()
                            .setText("Hello world!")
                            .setFontStyle(new FontStyle.Builder()
                                .setColor(argb(0xFF000000)).build()
                            ).build()
                        ).build()
                    ).build()
                ).build()
            ).build()
        );
   }

   @NonNull
   @Override
   protected ListenableFuture<Resources> onResourcesRequest(
       @NonNull ResourcesRequest requestParams
   ) {
       return Futures.immediateFuture(new 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=".MyTileService"
   android:label="@string/tile_label"
   android:description="@string/tile_description"
   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 ô.

Người dùng sẽ thấy biểu tượng, nhãn và nội dung mô tả khi định cấu hình ô trên điện thoại hoặc đồng hồ.

Hãy dùng thẻ siêu dữ liệu xem trước để hiển thị bản xem trước của ô khi bạn định cấu hình ô trên điện thoại.

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

Bố cục của ô được viết bằng mẫu trình tạo. Bố cục của ô được thiết kế giống một cây bao gồm các vùng chứa bố cục và các phần tử của bố cục cơ bản. Mỗi phần tử của bố cục có các thuộc tính mà bạn có thể thiết lập thông qua nhiều phương thức setter.

Phần tử của bố cục cơ bản

Sau đây là các phần tử hình ảnh được hỗ trợ:

  • Text: hiển thị một chuỗi văn bản (không bắt buộc phải gói văn bản đó).
  • Image: hiển thị một hình ảnh.
  • Spacer: cung cấp khoảng đệm giữa các phần tử hoặc có thể hoạt động như một đường phân chia khi bạn đặt màu nền.

Thành phần Material

Ngoài các phần tử cơ bản, thư viện tiles-material còn cung cấp các thành phần đảm bảo thiết kế ô phù hợp với các đề xuất về giao diện người dùng Material Design.

  • Button: thành phần hình tròn có thể nhấp vào, được thiết kế để chứa một biểu tượng.
  • Chip: thành phần có hình dạng sân vận động có thể nhấp vào, được thiết kế để chứa tối đa 2 dòng văn bản và một biểu tượng không bắt buộc.
  • CompactChip: thành phần có hình dạng sân vận động có thể nhấp vào, được thiết kế để chứa một dòng văn bản.
  • TitleChip: thành phần có hình dạng sân vận động có thể nhấp vào, giống như Chip nhưng có chiều cao lớn hơn để chứa đủ văn bản tiêu đề.
  • CircularProgressIndicator: chỉ báo tiến trình hình tròn có thể đặt vào bên trong ProgressIndicatorLayout để hiển thị tiến trình xung quanh các cạnh của màn hình.

Vùng chứa bố cục

Sau đây là các vùng chứa được hỗ trợ:

  • Row: sắp xếp lần lượt từng phần tử con theo chiều ngang.
  • Column: sắp xếp lần lượt từng phần tử con theo chiều dọc.
  • Box: xếp chồng các phần tử con lên nhau.
  • Arc: sắp xếp các phần tử con trong một hình tròn.
  • Spannable: áp dụng FontStyles cụ thể cho các phần văn bản cùng với văn bản và hình ảnh xen kẽ. Để biết thêm thông tin, hãy xem phần Spannable.

Mỗi vùng chứa có thể chứa một hoặc nhiều phần tử con, mà chính các phần tử đó cũng có thể là vùng chứa. Ví dụ: Column có thể chứa nhiều phần tử Row dưới dạng phần tử con, từ đó tạo ra một bố cục giống như lưới.

Ví dụ: ô có 1 bố cục vùng chứa và 2 phần tử bố cục con có thể có dạng như sau:

Kotlin

private fun myLayout(): LayoutElement =
    Row.Builder()
        .setWidth(wrap())
        .setHeight(expand())
        .setVerticalAlignment(VALIGN_BOTTOM)
        .addContent(Text.Builder()
            .setText("Hello world")
            .build()
        )
        .addContent(Image.Builder()
            .setResourceId("image_id")
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .build()
        ).build()

Java

private LayoutElement myLayout() {
    return new Row.Builder()
        .setWidth(wrap())
        .setHeight(expand())
        .setVerticalAlignment(VALIGN_BOTTOM)
        .addContent(new Text.Builder()
            .setText("Hello world")
            .build()
        )
        .addContent(new Image.Builder()
            .setResourceId("image_id")
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .build()
        ).build();
}

Bố cục Material

Ngoài bố cục cơ bản, thư viện tiles-material còn cung cấp một số bố cục ổn định để giữ những phần tử trong các "khung" cụ thể.

  • PrimaryLayout: đặt một hành động chính CompactChip ở dưới cùng với nội dung nằm ở giữa phía trên.
  • MultiSlotLayout: đặt nhãn chính và nhãn phụ có nội dung không bắt buộc nằm ở giữa và CompactChip không bắt buộc ở dưới cùng.
  • ProgressIndicatorLayout: đặt CircularProgressIndicator xung quanh các cạnh của màn hình và đặt nội dung đã cho vào bên trong.

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

Công cụ 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 công cụ 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 công cụ sửa đổi có thể nhấp để ô 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 ô.

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:

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 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 ô "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:

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();
}

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 onResourcesRequest() 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 onResourcesRequest():

Kotlin

override fun onResourcesRequest(
    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> onResourcesRequest(
       @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()
);
}