Tạo thẻ thông tin đầu tiên trong Wear OS

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

1. Giới thiệu

đồng hồ ảnh động, người dùng vuốt mặt đồng hồ sang thẻ thông tin đầu tiên là thông tin dự báo, sau đó đến thẻ thông tin hẹn giờ rồi quay lại

Thẻ thông tin Wear OS giúp bạn dễ dàng truy cập thông tin và các hành động mà người dùng cần để hoàn thành công việc. Chỉ cần thao tác vuốt từ mặt đồng hồ, người dùng có thể thấy thông tin dự báo mới nhất hoặc khởi động đồng hồ hẹn giờ.

Thẻ thông tin chạy dưới dạng một phần giao diện người dùng hệ thống thay vì chạy trong vùng chứa ứng dụng. Chúng ta sẽ sử dụng Dịch vụ để mô tả bố cục và nội dung của thẻ thông tin. Sau đó, giao diện người dùng hệ thống sẽ hiển thị thẻ thông tin khi cần.

Bạn sẽ thực hiện

35a459b77a2c9d52.png

Bạn sẽ tạo một thẻ thông tin cho một ứng dụng nhắn tin để cho thấy các cuộc trò chuyện gần đây. Từ bề mặt này, người dùng có thể chuyển thẳng đến 1 trong 3 nhiệm vụ phổ biến:

  • Mở một cuộc trò chuyện
  • Tìm kiếm một cuộc trò chuyện
  • Soạn một tin nhắn mới

Kiến thức bạn sẽ học được

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách viết Thẻ thông tin dành cho Wear OS của riêng mình, bao gồm cách:

  • Tạo một TileService
  • Thử nghiệm thẻ thông tin trên thiết bị
  • Xem trước giao diện người dùng của thẻ thông tin trong Android Studio
  • Phát triển giao diện người dùng của thẻ thông tin
  • Thêm hình ảnh
  • Xử lý các lượt tương tác

Điều kiện tiên quyết

  • Hiểu biết cơ bản về Kotlin

2. Chuẩn bị

Ở bước này, bạn sẽ thiết lập môi trường và tải dự án ban đầu xuống.

Bạn cần có

  • Android Studio Dolphin (2021.3.1) trở lên
  • Trình mô phỏng hoặc thiết bị Wear OS

Trước khi bắt đầu, nếu bạn chưa quen dùng Wear OS, hãy đọc hướng dẫn nhanh hữu ích này. Hướng dẫn trên bao gồm hướng dẫn thiết lập trình mô phỏng Wear OS và mô tả cách sử dụng hệ thống.

Tải mã xuống

Nếu đã cài đặt git, bạn chỉ cần chạy lệnh dưới đây để sao chép mã từ kho lưu trữ này. Để kiểm tra xem git đã được cài đặt hay chưa, hãy nhập git –version vào dòng lệnh hoặc cửa sổ dòng lệnh và xác minh rằng mã này được thực thi đúng cách.

git clone https://github.com/googlecodelabs/wear-tiles.git
cd wear-tiles

Nếu không có git, bạn có thể nhấp vào nút sau đây để tải tất cả mã dành cho lớp học lập trình này:

Mở dự án trong Android Studio

Trên cửa sổ "Welcome to Android Studio" (Chào mừng bạn đến với Android Studio), hãy chọn c01826594f360d94.png Open an Existing Project (Mở một Dự án hiện có) hoặc File > Open (Tệp > Mở) rồi chọn thư mục [Download Location].

3. Tạo thẻ thông tin cơ bản

Điểm truy cập của một thẻ thông tin là dịch vụ thẻ thông tin. Ở bước này, bạn sẽ đăng ký dịch vụ và xác định bố cục cho thẻ thông tin.

HelloWorldTileService

Một lớp triển khai TileService cần chỉ định hai hàm:

  • onResourcesRequest(requestParams: ResourcesRequest): ListenableFuture<Resources>
  • onTileRequest(requestParams: TileRequest): ListenableFuture<Tile>

Hàm đầu tiên liên kết mã nhận dạng chuỗi với một tài nguyên hình ảnh. Đây là nơi cung cấp tài nguyên hình ảnh mà chúng ta sẽ sử dụng trong thẻ thông tin.

Hàm thứ hai trả về nội dung mô tả thẻ thông tin bao gồm cả bố cục. Đây là nơi chúng ta xác định bố cục thẻ thông tin và cách dữ liệu liên kết với bố cục này.

Mở HelloWorldTileService.kt từ mô-đun start. Tất cả thay đổi mà bạn thực hiện sẽ có mặt ở mô-đun trên. Ngoài ra, chúng tôi còn cung cấp mô-đun finished nếu bạn muốn xem kết quả của lớp học lập trình.

HelloWorldTileService mở rộng CoroutinesTileService, một trình bao bọc phù hợp với coroutine Kotlin trong thư viện Thẻ thông tin Horologist. Horologist là một nhóm thư viện của Google để bổ sung các tính năng nhà phát triển Wear OS thường yêu cầu nhưng vẫn chưa xuất hiện trên Jetpack.

CoroutinesTileService cung cấp hai hàm tạm ngưng (là các phiên bản coroutine của những hàm trong TileService):

  • suspend resourcesRequest(requestParams: ResourcesRequest): Resources
  • suspend tileRequest(requestParams: TileRequest): Tile

Để tìm hiểu thêm về coroutine, hãy xem tài liệu về Coroutine Kotlin trên Android.

HelloWorldTileService vẫn chưa hoàn tất. Chúng tôi cần đăng ký dịch vụ trong tệp kê khai và cũng cần triển khai tileLayout.

Đăng ký dịch vụ thẻ thông tin

Bạn cần phải đăng ký dịch vụ thẻ thông tin trong tệp kê khai để hệ thống biết được. Sau khi được đăng ký, dịch vụ sẽ xuất hiện trong danh sách các thẻ thông tin hiện có để người dùng thêm vào.

Thêm <service> bên trong phần tử <application>:

start/src/main/AndroidManifest.xml

<service
    android:name="com.example.wear.tiles.hello.HelloWorldTileService"
    android:icon="@drawable/ic_waving_hand_24"
    android:label="@string/hello_tile_label"
    android:description="@string/hello_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>

    <!-- The tile preview shown when configuring tiles on your phone -->
    <meta-data
        android:name="androidx.wear.tiles.PREVIEW"
        android:resource="@drawable/tile_hello" />
</service>

Biểu tượng và nhãn được dùng (dưới dạng phần giữ chỗ) khi thẻ thông tin tải lần đầu, hoặc nếu xảy ra lỗi khi tải thẻ thông tin. Tiếp đó, siêu dữ liệu ở phía cuối xác định hình ảnh xem trước, được hiển thị trong băng chuyền khi người dùng thêm một thẻ thông tin.

Xác định bố cục cho thẻ thông tin

HelloWorldTileService có một hàm tên là tileLayout, chứa TODO() là phần nội dung. Hãy thay hàm này bằng phương thức triển khai, nơi chúng ta xác định bố cục cho thẻ thông tin và liên kết dữ liệu:

start/src/main/java/com/example/wear/tiles/hello/HelloWorldTileService.kt

private fun tileLayout(): LayoutElement {
    val text = getString(R.string.hello_tile_body)
    return LayoutElementBuilders.Box.Builder()
        .setVerticalAlignment(LayoutElementBuilders.VERTICAL_ALIGN_CENTER)
        .setWidth(DimensionBuilders.expand())
        .setHeight(DimensionBuilders.expand())
        .addContent(
            LayoutElementBuilders.Text.Builder()
                .setText(text)
                .build()
        )
        .build()
}

Chúng ta sẽ tạo một phần tử Text và thiết lập phần tử này bên trong Box để có thể tiến hành một số thao tác căn chỉnh cơ bản.

Và đó là Thẻ thông tin Wear OS đầu tiên bạn tạo ra! Hãy cài đặt và xem giao diện của thẻ thông tin này.

4. Thử nghiệm thẻ thông tin của bạn trên một thiết bị

Với mô-đun bắt đầu được chọn trong trình đơn thả xuống của mục chạy cấu hình, bạn có thể cài đặt ứng dụng (mô-đun start) trên thiết bị hoặc trình mô phỏng và cài đặt thẻ thông tin theo cách thủ công như người dùng vẫn thường thao tác.

Thay vào đó, hãy sử dụng Direct Surface Launch, một tính năng ra mắt cùng với Android Studio Dolphin, để tạo cấu hình chạy mới nhằm khởi chạy thẻ thông tin ngay trên Android Studio. Chọn "Edit Configurations…" (Chỉnh sửa cấu hình…) trong trình đơn thả xuống ở bảng trên cùng.

Trình đơn thả xuống để chạy cấu hình ở bảng trên cùng trong Android Studio. Trình đơn Chỉnh sửa cấu hình được đánh dấu.

Nhấp vào nút "Thêm cấu hình mới" rồi chọn "Thẻ thông tin trong Wear OS". Thêm tên mô tả, sau đó chọn mô-đun Tiles_Code_Lab.start và thẻ thông tin HelloWorldTileService.

Nhấn "OK" để hoàn tất.

Trình đơn Chỉnh sửa cấu hình chứa Thẻ thông tin Wear OS có tên HelloTile đang được định cấu hình.

Direct Surface Launch cho phép chúng ta nhanh chóng kiểm tra thẻ thông tin trên trình mô phỏng hoặc thiết bị Wear OS thực tế. Hãy dùng thử bằng cách chạy "HelloTile". Giao diện sẽ giống như ảnh chụp màn hình dưới đây.

Đồng hồ tròn cho thấy dòng chữ màu trắng "Time to create a tile!" ("Đã đến lúc tạo thẻ thông tin!") trên nền đen

5. Tạo một thẻ thông tin cho ứng dụng nhắn tin

Đồng hồ tròn cho thấy 5 nút tròn được sắp xếp theo hình kim tự tháp 2x3. Nút đầu tiên và thứ 3 cho thấy tên viết tắt bằng chữ màu tím, nút thứ 2 và thứ 4 cho thấy ảnh hồ sơ, và nút cuối cùng là biểu tượng tìm kiếm. Bên dưới các nút là một khối nhỏ gọn màu tím có nội dung "New" (Mới) với văn bản màu đen.

Thẻ thông tin cho ứng dụng nhắn tin chúng ta sắp tạo có tính đặc trưng của một thẻ thông tin thực tế. Không giống như ví dụ về HelloWorld, ví dụ này tải dữ liệu từ kho lưu trữ cục bộ, tìm nạp hình ảnh từ mạng để hiển thị và xử lý hoạt động tương tác để mở ứng dụng ngay trong thẻ thông tin.

MessagingTileService

MessagingTileService mở rộng lớp CoroutinesTileService mà chúng ta đã thấy trước đó.

Điểm khác biệt chính giữa ví dụ này và ví dụ trước là hiện tại chúng ta đang theo dõi dữ liệu từ kho lưu trữ, đồng thời tìm nạp dữ liệu hình ảnh từ trên mạng.

Đối với nhiệm vụ có thể chạy trong thời gian dài (ví dụ: lệnh gọi mạng), bạn nên dùng những lệnh như WorkManager, vì hàm của dịch vụ thẻ thông tin có thời gian chờ tương đối ngắn. Trong lớp học lập trình này, chúng tôi sẽ không giới thiệu về WorkManager. Để tự tìm hiểu, hãy xem lớp học lập trình này.

MessagingTileRenderer

MessagingTileRenderer mở rộng lớp TileRenderer (một lớp trừu tượng khác trong Thẻ thông tin Horologist). Nó hoàn toàn đồng bộ, trạng thái được chuyển vào các hàm kết xuất, giúp bạn dễ dàng sử dụng hơn trong các kiểm thử và bản xem trước Android Studio.

Ở bước tiếp theo, chúng ta sẽ xem cách thêm bản xem trước trên Android Studio cho thẻ thông tin.

6. Thêm hàm xem trước

Chúng ta có thể xem trước giao diện người dùng thẻ thông tin trong Android Studio bằng cách sử dụng TileLayoutPreview (và các hàm tương tự) trong Thẻ thông tin Horologist. Hành động này rút ngắn vòng hồi tiếp khi phát triển giao diện người dùng, giúp quá trình lặp lại diễn ra nhanh hơn nhiều so với trước đây.

Chúng ta sẽ sử dụng công cụ của Jetpack Compose để xem bản xem trước. Đó là lý do bạn nhìn thấy chú thích @Composable trong hàm xem trước dưới đây. Bạn vẫn có thể tìm hiểu thêm về bản xem trước thành phần kết hợpmà không cần hoàn thành lớp học lập trình.

Thêm bản xem trước thành phần kết hợp cho MessagingTileRenderer ở cuối tệp.

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

@WearDevicePreview
@Composable
fun MessagingTileRendererPreview() {
    TileLayoutPreview(
        state = MessagingTileState(MessagingRepo.knownContacts),
        resourceState = emptyMap(),
        renderer = MessagingTileRenderer(LocalContext.current)
    )
}

Lưu ý rằng hàm có khả năng kết hợp sử dụng TileLayoutPreview, do đó, chúng ta không thể trực tiếp xem trước bố cục thẻ thông tin.

Sử dụng chế độ chỉnh sửa "Split" để xem bản xem trước của thẻ thông tin:

chế độ xem chia đôi màn hình của Android Studio với mã xem trước ở bên trái và hình ảnh thẻ thông tin ở bên phải.

Chúng ta đang truyền dữ liệu nhân tạo trong MessagingTileState và (chưa) có trạng thái tài nguyên để có thể truyền một bản đồ trống.

Ở bước tiếp theo, chúng ta sẽ sử dụng Tiles Material để cập nhật bố cục.

7. Thêm Tiles Material

Tiles Material cung cấp các thành phần và bố cục Material tạo sẵn, cho phép bạn tạo các thẻ thông tin phù hợp với thiết kế Material Design mới nhất cho Wear OS.

Thêm phần phụ thuộc Tiles Material vào tệp build.gradle:

start/build.gradle

implementation "androidx.wear.tiles:tiles-material:$tilesVersion"

Tuỳ vào độ phức tạp của thiết kế, bạn nên sắp xếp bố cục với trình kết xuất bằng cách sử dụng các hàm cấp cao nhất trong cùng một tệp, để đóng gói đơn vị logic của giao diện người dùng.

Thêm mã cho nút vào cuối tệp kết xuất và bản xem trước:

start/src/main/java/MessagingTileRenderer.kt

private fun searchLayout(
    context: Context,
    clickable: ModifiersBuilders.Clickable,
) = Button.Builder(context, clickable)
    .setContentDescription(context.getString(R.string.tile_messaging_search))
    .setIconContent(MessagingTileRenderer.ID_IC_SEARCH)
    .setButtonColors(ButtonColors.secondaryButtonColors(MessagingTileTheme.colors))
    .build()

@IconSizePreview
@Composable
private fun SearchButtonPreview() {
    LayoutElementPreview(
        searchLayout(
            context = LocalContext.current,
            clickable = emptyClickable
        )
    ) {
        addIdToImageMapping(
            MessagingTileRenderer.ID_IC_SEARCH,
            drawableResToImageResource(R.drawable.ic_search_24)
        )
    }
}

LayoutElementPreview tương tự như TileLayoutPreview nhưng được dùng cho các thành phần riêng lẻ như nút, khối hoặc nhãn. Biểu thức trailing lambda ở cuối cho phép chúng ta chỉ định liên kết mã tài nguyên (đến tài nguyên hình ảnh), vì vậy ở đây chúng ta đang liên kết ID_IC_SEARCH đến tài nguyên tìm kiếm hình ảnh.

Khi sử dụng chế độ chỉnh sửa "Split", chúng ta có thể xem trước nút tìm kiếm:

Một nhóm các bản xem trước xếp chồng theo chiều dọc, thẻ thông tin ở trên cùng và nút biểu tượng tìm kiếm ở bên dưới.

Chúng ta cũng có thể làm tương tự để tạo bố cục cho danh bạ:

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

private fun contactLayout(
    context: Context,
    contact: Contact,
    clickable: ModifiersBuilders.Clickable,
) = Button.Builder(context, clickable)
    .setContentDescription(contact.name)
    .apply {
        if (contact.avatarUrl != null) {
            setImageContent(contact.imageResourceId())
        } else {
            setTextContent(contact.initials)
            setButtonColors(ButtonColors.secondaryButtonColors(MessagingTileTheme.colors))
        }
    }
    .build()

Tiles Material không chỉ bao gồm các thành phần. Thay vì sử dụng một loạt các cột và hàng lồng nhau, chúng ta có thể dùng bố cục trong Tiles Material để nhanh chóng tạo được giao diện mong muốn.

Ở đây, chúng ta có thể sử dụng PrimaryLayoutMultiButtonLayout để sắp xếp 4 địa chỉ liên hệ và nút tìm kiếm. Cập nhật hàm messagingTileLayout() trong MessagingTileRenderer với các bố cục sau:

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

private fun messagingTileLayout(
    context: Context,
    deviceParameters: DeviceParametersBuilders.DeviceParameters,
    state: MessagingTileState
) = PrimaryLayout.Builder(deviceParameters)
    .setContent(
        MultiButtonLayout.Builder()
            .apply {
                // In a PrimaryLayout with a compact chip at the bottom, we can fit 5 buttons.
                // We're only taking the first 4 contacts so that we can fit a Search button too.
                state.contacts.take(4).forEach { contact ->
                    addButtonContent(
                        contactLayout(
                            context = context,
                            contact = contact,
                            clickable = emptyClickable
                        )
                    )
                }
            }
            .addButtonContent(searchLayout(context, emptyClickable))
            .build()
    )
    .build()

Bản xem trước thẻ thông tin có 5 nút được đặt trong hình kim tự tháp 2x3. Nút thứ 2 và thứ 3 là các vòng tròn tô màu xanh lam, biểu thị hình ảnh còn thiếu.

MultiButtonLayout hỗ trợ tối đa 7 nút và bố trí các nút với khoảng cách phù hợp. Hãy thêm khối "New" (Mới) vào PrimaryLayout , trên trình tạo PrimaryLayout trong hàm messagingTileLayout():

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

.setPrimaryChipContent(
    CompactChip.Builder(
        /* context = */ context,
        /* text = */ context.getString(R.string.tile_messaging_create_new),
        /* clickable = */ emptyClickable,
        /* deviceParameters = */ deviceParameters
    )
        .setChipColors(ChipColors.primaryChipColors(MessagingTileTheme.colors))
        .build()
)

bản xem trước thẻ thông tin có 5 nút và một khối nhỏ gọn bên dưới với nội dung "new" (mới)

Ở bước tiếp theo, chúng ta sẽ thêm những hình ảnh còn thiếu.

8. Thêm hình ảnh

Hiển thị hình ảnh cục bộ trên thẻ thông tin là một nhiệm vụ đơn giản, đó là cung cấp một mối liên kết từ mã nhận dạng chuỗi (mà bạn sử dụng trong bố cục) cho hình ảnh, sau đó sử dụng hàm tiện lợi trong Thẻ thông tin Horologist để tải đối tượng có thể vẽ rồi chuyển đổi đối tượng này thành tài nguyên hình ảnh. Có một ví dụ trong SearchButtonPreview:

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

addIdToImageMapping(
    ID_IC_SEARCH,
    drawableResToImageResource(R.drawable.ic_search_24)
)

Đối với thẻ thông tin cho ứng dụng nhắn tin, chúng ta cũng cần tải hình ảnh không chỉ từ tài nguyên cục bộ mà còn từ trên mạng. Để làm điều đó, chúng ta dùng Coil, một trình tải hình ảnh dựa trên coroutine của Kotlin.

Mã sau đây được viết sẵn để thực hiện việc này:

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileService.kt

override suspend fun resourcesRequest(requestParams: ResourcesRequest): Resources {
    val avatars = imageLoader.fetchAvatarsFromNetwork(
        context = this@MessagingTileService,
        requestParams = requestParams,
        tileState = latestTileState()
    )
    return renderer.produceRequestedResources(avatars, requestParams)
}

Vì trình kết xuất thẻ thông tin hoàn toàn đồng bộ, nên dịch vụ thẻ thông tin là nội dung tìm nạp các bitmap từ trên mạng. Như trước đây, bạn nên sử dụng WorkManager để tìm nạp trước hình ảnh tuỳ thuộc vào kích thước, nhưng đối với lớp học lập trình này chúng ta sẽ trực tiếp tìm nạp các hình ảnh đó.

Chúng ta truyền bản đồ avatars (Contact đến Bitmap) đến trình kết xuất dưới dạng "trạng thái" cho các tài nguyên. Giờ đây, trình kết xuất có thể chuyển đổi các bitmap này thành tài nguyên hình ảnh cho thẻ thông tin.

Mã này cũng đã được viết:

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

override fun ResourceBuilders.Resources.Builder.produceRequestedResources(
    resourceState: Map<Contact, Bitmap>,
    deviceParameters: DeviceParametersBuilders.DeviceParameters,
    resourceIds: MutableList<String>
) {
    addIdToImageMapping(
        ID_IC_SEARCH,
        drawableResToImageResource(R.drawable.ic_search_24)
    )

    resourceState.forEach { (contact, bitmap) ->
        addIdToImageMapping(
            /* id = */ contact.imageResourceId(),
            /* image = */ bitmap.toImageResource()
        )
    }
}

Vì vậy, nếu dịch vụ đang tìm nạp bitmap và trình kết xuất đang chuyển đổi bitmap này thành tài nguyên hình ảnh, tại sao thẻ thông tin lại không hiển thị hình ảnh?

Có chứ! Nếu bạn chạy thẻ thông tin trên một thiết bị (có quyền truy cập Internet), bạn sẽ thấy các hình ảnh thực sự tải. Vấn đề chỉ đơn giản là vì bản xem trước, do chúng ta vẫn đang truyền emptyMap() cho resourceState.

Đối với thẻ thông tin thực tế, chúng ta đang tìm nạp bitmap từ trên mạng và ánh xạ bitmap này đến các địa chỉ liên hệ, nhưng chúng ta không cần dùng mạng đối với bản xem trước và thử nghiệm.

Cập nhật MessagingTileRendererPreview() để cung cấp bitmap cho hai địa chỉ liên hệ cần một:

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

@WearDevicePreview
@Composable
fun MessagingTileRendererPreview() {
    val state = MessagingTileState(MessagingRepo.knownContacts)
    val context = LocalContext.current
    TileLayoutPreview(
        state = state,
        resourceState = mapOf(
            state.contacts[1] to (context.getDrawable(R.drawable.ali) as BitmapDrawable).bitmap,
            state.contacts[2] to (context.getDrawable(R.drawable.taylor) as BitmapDrawable).bitmap,
        ),
        renderer = MessagingTileRenderer(context)
    )
}

Bây giờ, nếu chúng ta làm mới bản xem trước, những hình ảnh đó sẽ hiển thị:

bản xem trước thẻ thông tin có 5 nút, lần này trong 2 nút với vòng tròn được tô màu xanh lam trước đó đã có hình ảnh

Ở bước tiếp theo, chúng ta sẽ xử lý các lượt nhấp vào từng thành phần.

9. Xử lý các lượt tương tác

Một trong những điều hữu ích nhất mà thẻ thông tin mang lại là cung cấp lối tắt đến hành trình trọng yếu của người dùng. Khác với trình chạy ứng dụng chỉ mở ứng dụng, ở đây chúng ta có không gian để cung cấp các lối tắt theo ngữ cảnh vào một màn hình cụ thể trong ứng dụng.

Cho đến nay, chúng ta đã sử dụng emptyClickable cho chip (khối) và mỗi nút. Bạn có thể làm điều này cho các bản xem trước không có tính tương tác, nhưng hãy tìm hiểu cách thêm thao tác cho các thành phần.

Hai trình tạo từ lớp 'ActionBuilders' xác định các hành động có thể nhấp là LoadActionLaunchAction.

LoadAction

Bạn có thể sử dụng LoadAction nếu muốn thực hiện logic trong dịch vụ thẻ thông tin khi người dùng nhấp vào một phần tử, ví dụ: tăng một bộ đếm.

.setClickable(
    Clickable.Builder()
        .setId(ID_CLICK_INCREMENT_COUNTER)
        .setOnClick(ActionBuilders.LoadAction.Builder().build())
        .build()
    )
)

Khi người dùng nhấp vào nút này, onTileRequest sẽ được gọi trong dịch vụ (tileRequest trong CoroutinesTileService). Vì vậy, đây là cơ hội tốt để làm mới giao diện người dùng thẻ thông tin:

override suspend fun tileRequest(requestParams: TileRequest): Tile {
    if (requestParams.state.lastClickableId == ID_CLICK_INCREMENT_COUNTER) {
        // increment counter
    }
    // return an updated tile
}

LaunchAction

Bạn có thể dùng LaunchAction để chạy một hoạt động. Trong MessagingTileRenderer, hãy cập nhật khả năng nhấp cho nút tìm kiếm.

Nút tìm kiếm được xác định bằng hàm searchLayout() trong MessagingTileRenderer. Hàm này đã lấy Clickable làm tham số. Tuy nhiên, tính đến thời điểm hiện tại, chúng ta đã truyền emptyClickable. Đây là phương thức triển khai không hoạt động, không thực hiện bất kỳ hành động nào khi người dùng nhấp vào nút trên.

Hãy cập nhật messagingTileLayout() để truyền hành động nhấp thật. Thêm tham số searchButtonClickable rồi truyền tham số đó vào searchLayout():

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

private fun messagingTileLayout(
    context: Context,
    deviceParameters: DeviceParametersBuilders.DeviceParameters,
    state: MessagingTileState,
    searchButtonClickable: ModifiersBuilders.Clickable
...
    .addButtonContent(searchLayout(context, searchButtonClickable))

Chúng ta cũng cần cập nhật renderTile, đây chính là nơi gọi messagingTileLayout do vừa thêm một tham số mới (searchButtonClickable). Sau đó, chúng ta sẽ sử dụng hàm launchActivityClickable() để tạo một hàm mới có thể nhấp và truyền openSearch() ActionBuilder dưới dạng thao tác:

start/src/main/java/com/example/wear/tiles/messaging/tile/MessagingTileRenderer.kt

override fun renderTile(
    state: MessagingTileState,
    deviceParameters: DeviceParametersBuilders.DeviceParameters
): LayoutElementBuilders.LayoutElement {
    return messagingTileLayout(
        context = context,
        deviceParameters = deviceParameters,
        state = state,
        searchButtonClickable = launchActivityClickable("search_button", openSearch())
    )
}

Mở launchActivityClickable để xem cách hoạt động (đã được xác định) của hàm:

start/src/main/java/com/example/wear/tiles/messaging/tile/ClickableActions.kt

internal fun launchActivityClickable(
    clickableId: String,
    androidActivity: ActionBuilders.AndroidActivity
) = ModifiersBuilders.Clickable.Builder()
    .setId(clickableId)
    .setOnClick(
        ActionBuilders.LaunchAction.Builder()
            .setAndroidActivity(androidActivity)
            .build()
    )
    .build()

Cách hoạt động rất giống với LoadAction – điểm khác biệt chính là chúng ta gọi setAndroidActivity. Trong cùng một tệp, chúng ta có nhiều ví dụ về ActionBuilder.AndroidActivity.

Đối với openSearch được dùng cho khả năng nhấp này, ta gọi setMessagingActivity và truyền thêm một chuỗi để xác định đây là lượt nhấp vào nút nào.

start/src/main/java/com/example/wear/tiles/messaging/tile/ClickableActions.kt

internal fun openSearch() = ActionBuilders.AndroidActivity.Builder()
    .setMessagingActivity()
    .addKeyToExtraMapping(
        MainActivity.EXTRA_JOURNEY,
        ActionBuilders.stringExtra(MainActivity.EXTRA_JOURNEY_SEARCH)
    )
    .build()

...

internal fun ActionBuilders.AndroidActivity.Builder.setMessagingActivity(): ActionBuilders.AndroidActivity.Builder {
    return setPackageName("com.example.wear.tiles")
        .setClassName("com.example.wear.tiles.messaging.MainActivity")
}

Chạy thẻ thông tin rồi nhấp vào nút tìm kiếm. Thao tác này sẽ mở MainActivity và hiển thị văn bản để xác nhận nút tìm kiếm đã được nhấp vào.

Cách thêm thao tác cho các nút khác cũng tương tự như vậy. ClickableActions chứa các hàm bạn cần. Nếu bạn cần gợi ý, hãy xem MessagingTileRenderer trong mô-đun finished.

10. Xin chúc mừng

Xin chúc mừng! Bạn đã tìm hiểu cách xây dựng thẻ thông tin dành cho Wear OS!

Tiếp theo là gì?

Để biết thêm thông tin, hãy xem các phương pháp triển khai Thẻ thông tin Golden trên GitHubhướng dẫn về Thẻ thông tin trong Wear OS.