Mulai menggunakan kartu

Untuk mulai menyediakan kartu dari aplikasi, sertakan dependensi berikut dalam file build.gradle aplikasi.

Groovy

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

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

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

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

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

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

Kotlin

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

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

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

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

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

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

Membuat kartu

Untuk menyediakan kartu dari aplikasi, buat class yang memperluas TileService dan implementasikan metode tersebut, seperti ditunjukkan dalam contoh kode berikut:

Kotlin

// Uses the ProtoLayout namespace for tile timeline objects.
// If you haven't done so already, migrate to the ProtoLayout namespace.
import androidx.wear.protolayout.TimelineBuilders.Timeline
import androidx.wear.protolayout.material.Text
import androidx.wear.tiles.TileBuilders.Tile

private val RESOURCES_VERSION = "1"
class MyTileService : TileService() {
    override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
        Futures.immediateFuture(Tile.Builder()
            .setResourcesVersion(RESOURCES_VERSION)
            .setTileTimeline(
                Timeline.fromLayoutElement(
                    Text.Builder(this, "Hello world!")
                        .setTypography(Typography.TYPOGRAPHY_DISPLAY1)
                        .setColor(argb(0xFF000000.toInt()))
                        .build()))
            .build())

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

Java

// Uses the ProtoLayout namespace for tile timeline objects.
// If you haven't done so already, migrate to the ProtoLayout namespace.
import androidx.wear.protolayout.TimelineBuilders.Timeline;
import androidx.wear.protolayout.material.Text;
import androidx.wear.tiles.TileBuilders.Tile;

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)
            .setTileTimeline(
                Timeline.fromLayoutElement(
                    new Text.Builder(this, "Hello world!")
                        .setTypography(Typography.TYPOGRAPHY_DISPLAY1)
                        .setColor(ColorBuilders.argb(0xFF000000))
                        .build()))
            .build()
        );
   }

   @NonNull
   @Override
   protected ListenableFuture<Resources> onTileResourcesRequest(
       @NonNull ResourcesRequest requestParams
   ) {
       return Futures.immediateFuture(new Resources.Builder()
               .setVersion(RESOURCES_VERSION)
               .build()
       );
   }
}

Selanjutnya, tambahkan layanan di dalam tag <application> file AndroidManifest.xml Anda.

<service
   android:name=".MyTileService"
   android:label="@string/tile_label"
   android:description="@string/tile_description"
   android:icon="@drawable/tile_icon_round"
   android:roundIcon="@drawable/tile_icon_round"
   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>

Filter intent dan izin akan mendaftarkan layanan ini sebagai penyedia kartu.

Ikon, label, dan deskripsi ditampilkan kepada pengguna saat mereka mengonfigurasi kartu di ponsel atau smartwatch.

Gunakan tag metadata pratinjau untuk menampilkan pratinjau kartu saat mengonfigurasinya di ponsel.

Ringkasan siklus proses layanan kartu

Setelah membuat dan mendeklarasikan TileService dalam manifes aplikasi, Anda dapat merespons perubahan status layanan kartu.

TileService adalah layanan terikat. TileService terikat sebagai hasil permintaan aplikasi atau jika sistem perlu berkomunikasi dengannya. Siklus proses layanan terikat standar berisi empat metode callback berikut: onCreate(), onBind(), onUnbind(), dan onDestroy(). Sistem memanggil metode ini setiap kali layanan memasuki fase siklus proses baru.

Selain callback yang mengontrol siklus proses layanan terikat, Anda dapat mengimplementasikan metode lain khusus untuk siklus proses TileService. Semua layanan kartu harus mengimplementasikan onTileRequest() dan onTileResourcesRequest() untuk merespons permintaan update dari sistem.

  • onTileAddEvent(): Sistem memanggil metode ini hanya saat pengguna menambahkan kartu Anda untuk pertama kalinya, serta jika pengguna menghapus dan menambahkan kartu Anda lagi. Ini adalah waktu terbaik untuk melakukan inisialisasi satu kali.

    onTileAddEvent() hanya dipanggil jika kumpulan kartu dikonfigurasi ulang, bukan setiap kali kartu dibuat oleh sistem. Misalnya, saat perangkat dimulai ulang atau dinyalakan, onTileAddEvent() tidak akan dipanggil untuk kartu yang telah ditambahkan. Sebagai gantinya, Anda dapat menggunakan getActiveTilesAsync() untuk mendapatkan snapshot tempat kartu milik Anda yang aktif.

  • onTileRemoveEvent(): Sistem memanggil metode ini hanya jika pengguna menghapus kartu Anda.

  • onTileEnterEvent(): Sistem memanggil metode ini saat kartu yang disediakan oleh penyedia ini muncul di layar.

  • onTileLeaveEvent(): Sistem memanggil metode ini saat kartu yang disediakan oleh penyedia ini tidak terlihat di layar.

  • onTileRequest(): Sistem memanggil metode ini saat sistem meminta linimasa baru dari penyedia ini.

  • onTileResourcesRequest(): Sistem memanggil metode ini saat sistem meminta paket resource dari penyedia ini. Hal ini dapat terjadi saat pertama Kartu dimuat atau setiap kali versi resource berubah.

Mengkueri kartu mana yang aktif

Kartu aktif adalah kartu yang telah ditambahkan untuk ditampilkan di smartwatch. Gunakan metode statis TileService getActiveTilesAsync() untuk mengkueri kartu yang termasuk dalam aplikasi Anda yang aktif.

Membuat UI untuk kartu

Tata letak kartu ditulis menggunakan pola builder. Tata letak kartu dibuat seperti hierarki yang terdiri dari penampung tata letak dan elemen tata letak dasar. Setiap elemen tata letak memiliki properti, yang dapat Anda setel melalui berbagai metode penyetel.

Elemen tata letak dasar

Elemen visual berikut dari library protolayout didukung, beserta komponen Material:

  • Text: merender string teks, yang digabungkan secara opsional.
  • Image: merender gambar.
  • Spacer: menyediakan padding di antara elemen atau dapat berfungsi sebagai pemisah saat Anda menetapkan warna latar belakangnya.

Komponen Material

Selain elemen dasar, library protolayout-material juga menyediakan komponen yang memastikan desain kartu sesuai dengan rekomendasi antarmuka pengguna Desain Material.

  • Button: komponen melingkar yang dapat diklik dan dirancang untuk memuat ikon.
  • Chip: komponen berbentuk elips yang dapat diklik dan dirancang untuk memuat hingga dua baris teks dan ikon opsional.

  • CompactChip: komponen berbentuk elips yang dapat diklik dan dirancang untuk memuat satu baris teks.

  • TitleChip: komponen berbentuk elips yang dapat diklik dan mirip dengan Chip tetapi lebih tinggi untuk menampung teks judul.

  • CircularProgressIndicator: indikator progres melingkar yang dapat ditempatkan di dalam EdgeContentLayout untuk menampilkan progres di sekitar tepi layar.

Penampung tata letak

Penampung berikut didukung, beserta tata letak Material:

  • Row: menata letak elemen turunan secara horizontal, satu per satu.
  • Column: menata letak elemen turunan secara vertikal, satu per satu.
  • Box: menempatkan elemen turunan satu per satu.
  • Arc: menata letak elemen turunan dalam lingkaran.
  • Spannable: menerapkan FontStyles khusus pada bagian teks beserta teks dan gambar yang disisipkan. Untuk informasi selengkapnya, lihat Spannable.

Setiap penampung dapat berisi satu atau beberapa turunan yang juga dapat berupa penampung. Misalnya, Column dapat berisi beberapa elemen Row sebagai turunan sehingga menghasilkan tata letak seperti petak.

Sebagai contoh, kartu dengan tata letak penampung dan dua elemen tata letak turunan dapat terlihat seperti ini:

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

Tata letak Material

Selain tata letak dasar, library protolayout-material juga menyediakan beberapa tata letak tetap yang dibuat untuk menampung elemen di "slot" tertentu.

  • PrimaryLayout: memosisikan satu tindakan utama CompactChip di bagian bawah dengan konten yang berpusat di atasnya.

  • MultiSlotLayout: memosisikan label utama dan sekunder dengan konten opsional di antara keduanya dan CompactChip opsional di bagian bawah.

  • MultiButtonLayout: mengatur posisi kumpulan tombol yang disusun sesuai dengan pedoman Material.

  • EdgeContentLayout: mengatur posisi konten di sekitar tepi layar, seperti CircularProgressIndicator. Saat menggunakan tata letak ini, margin dan padding yang sesuai secara otomatis diterapkan ke konten di dalamnya.

Arc

Turunan penampung Arc berikut didukung:

  • ArcLine: merender garis melengkung di sekitar Arc.
  • ArcText: merender teks melengkung di Arc.
  • ArcAdapter: merender elemen tata letak dasar di Arc, yang digambar bersinggungan dengan Arc.

Untuk informasi selengkapnya, lihat dokumentasi referensi untuk setiap jenis elemen.

Pengubah

Setiap elemen tata letak yang tersedia secara opsional dapat memiliki pengubah yang diterapkan padanya. Gunakan pengubah ini untuk tujuan berikut:

  • Mengubah tampilan visual tata letak. Misalnya, tambahkan latar belakang, batas, atau padding ke elemen tata letak.
  • Menambahkan metadata tentang tata letak. Misalnya, menambahkan pengubah semantik ke elemen tata letak untuk digunakan dengan pembaca layar.
  • Menambahkan fungsi. Misalnya, menambahkan pengubah yang dapat diklik ke elemen tata letak agar kartu Anda interaktif. Untuk mengetahui informasi selengkapnya, lihat Berinteraksi dengan kartu.

Misalnya, kita dapat menyesuaikan metadata dan tampilan default Image, seperti yang ditunjukkan dalam contoh kode berikut:

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 adalah jenis penampung khusus yang mengatur tata letak elemen yang mirip dengan teks. Jenis penampung ini berguna jika Anda ingin menerapkan gaya yang berbeda ke hanya satu substring dalam blok teks yang lebih besar, dan tidak mungkin dilakukan dengan elemen Text.

Penampung Spannable diisi dengan turunan Span. Turunan lain, atau instance Spannable bertingkat, tidak diizinkan.

Ada dua jenis turunan Span:

  • SpanText: merender teks dengan gaya tertentu.
  • SpanImage: merender gambar yang inline dengan teks.

Misalnya, Anda dapat mencetak miring kata "dunia" dalam kartu "Halo dunia" dan menyisipkan gambar di antara kata, seperti yang ditunjukkan dalam contoh kode berikut:

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

Menggunakan resource

Kartu tidak memiliki akses ke resource mana pun di aplikasi Anda. Ini berarti Anda tidak boleh meneruskan ID gambar Android ke elemen tata letak Image dan mengharapkannya untuk diselesaikan. Sebagai gantinya, ganti metode onTileResourcesRequest() dan sediakan resource apa pun secara manual.

Terdapat dua cara untuk menyediakan gambar dalam metode 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()
);
}