Pembuatan versi kartu

Di perangkat Wear OS, kartu ditampilkan oleh dua komponen utama dengan versi independen. Untuk memastikan kartu aplikasi Anda berfungsi dengan benar di semua perangkat, penting untuk memahami arsitektur dasarnya.

  • Library terkait kartu Jetpack: Library ini (termasuk Wear Tiles dan Wear ProtoLayout) disematkan di aplikasi Anda, dan Anda, sebagai developer, mengontrol versinya. Aplikasi Anda menggunakan library ini untuk membuat objek TileBuilder.Tile (struktur data yang merepresentasikan Petak Anda) sebagai respons terhadap panggilan onTileRequest() sistem.
  • Renderer ProtoLayout: Komponen sistem ini bertanggung jawab untuk merender objek Tile di layar dan menangani interaksi pengguna. Versi renderer tidak dikontrol oleh developer aplikasi dan dapat bervariasi di seluruh perangkat, bahkan perangkat dengan hardware yang identik.

Tampilan atau perilaku Kartu dapat bervariasi berdasarkan versi library Kartu Jetpack aplikasi Anda dan versi ProtoLayout Renderer di perangkat pengguna. Misalnya, satu perangkat mungkin mendukung rotasi atau tampilan data detak jantung, dan perangkat lain mungkin tidak.

Dokumen ini menjelaskan cara memastikan aplikasi Anda kompatibel dengan berbagai versi library Petak dan Perender ProtoLayout, serta cara bermigrasi ke versi library Jetpack yang lebih tinggi.

Pertimbangkan kompatibilitas

Untuk membuat Kartu yang berfungsi dengan benar di berbagai perangkat, pertimbangkan untuk memperhitungkan dukungan fitur yang bervariasi. Anda dapat melakukannya melalui dua strategi utama: mendeteksi kemampuan perender saat runtime dan menyediakan penggantian bawaan.

Mendeteksi kemampuan perender

Anda dapat mengubah tata letak kartu secara dinamis berdasarkan fitur yang tersedia di perangkat tertentu.

Mendeteksi versi perender

  • Gunakan metode getRendererSchemaVersion() dari objek DeviceParameters yang diteruskan ke metode onTileRequest() Anda. Metode ini menampilkan nomor versi utama dan minor ProtoLayout Renderer di perangkat.
  • Kemudian, Anda dapat menggunakan logika bersyarat dalam penerapan onTileRequest() untuk menyesuaikan desain atau perilaku Kartu berdasarkan versi perender yang terdeteksi.

Anotasi @RequiresSchemaVersion

  • Anotasi @RequiresSchemaVersion pada metode ProtoLayout menunjukkan versi skema perender minimum yang diperlukan agar metode tersebut berperilaku seperti yang didokumentasikan (contoh).
    • Meskipun memanggil metode yang memerlukan versi perender yang lebih tinggi daripada yang tersedia di perangkat tidak akan menyebabkan aplikasi Anda error, hal ini dapat menyebabkan konten tidak ditampilkan atau fitur diabaikan.

Contoh deteksi versi

val rendererVersion = requestParams.deviceConfiguration.rendererSchemaVersion

val arcElement =
    // DashedArcLine has the annotation @RequiresSchemaVersion(major = 1, minor = 500)
    // and so is supported by renderer versions 1.500 and greater
    if (
        rendererVersion.major > 1 ||
        (rendererVersion.major == 1 && rendererVersion.minor >= 500)
    ) {
        // Use DashedArcLine if the renderer supports it …
        DashedArcLine.Builder()
            .setLength(degrees(270f))
            .setThickness(8f)
            .setLinePattern(
                LayoutElementBuilders.DashedLinePattern.Builder()
                    .setGapSize(8f)
                    .setGapInterval(10f)
                    .build()
            )
            .build()
    } else {
        // … otherwise use ArcLine.
        ArcLine.Builder().setLength(degrees(270f)).setThickness(dp(8f)).build()
    }

Menyediakan Pengganti

Beberapa resource memungkinkan Anda menentukan penggantian langsung di builder. Hal ini sering kali lebih sederhana daripada memeriksa versi perender dan merupakan pendekatan yang lebih disukai jika tersedia.

Kasus penggunaan umum adalah menyediakan gambar statis sebagai penggantian untuk animasi Lottie. Jika perangkat tidak mendukung animasi Lottie, perangkat akan merender gambar statis.

val lottieImage =
    ResourceBuilders.ImageResource.Builder()
        .setAndroidLottieResourceByResId(
            ResourceBuilders.AndroidLottieResourceByResId.Builder(R.raw.lottie)
                .setStartTrigger(createOnVisibleTrigger())
                .build()
        )
        // Fallback if lottie is not supported
        .setAndroidResourceByResId(
            ResourceBuilders.AndroidImageResourceByResId.Builder()
                .setResourceId(R.drawable.lottie_fallback)
                .build()
        )
        .build()

Menguji dengan versi perender yang berbeda

Untuk menguji kartu Anda terhadap berbagai versi perender, deploy kartu ke berbagai versi emulator Wear OS. (Di perangkat fisik, update ProtoLayout Renderer diberikan oleh Play Store atau update sistem. Anda tidak dapat memaksa penginstalan versi perender tertentu.)

Fitur Pratinjau Petak Android Studio menggunakan perender yang disematkan di library ProtoLayout Jetpack yang menjadi dependensi kode Anda, jadi pendekatan lain adalah bergantung pada versi library Jetpack yang berbeda saat menguji petak.

Bermigrasi ke Tiles 1.5 / ProtoLayout 1.3 (Material 3 Ekspresif)

Perbarui library Petak Jetpack Anda untuk memanfaatkan peningkatan terbaru, termasuk perubahan UI agar Petak Anda terintegrasi dengan lancar ke dalam sistem.

Jetpack Tiles 1.5 dan Jetpack ProtoLayout 1.3 memperkenalkan beberapa peningkatan dan perubahan penting. Ini mencakup:

  • API seperti Compose untuk mendeskripsikan UI.
  • Komponen Material 3 Ekspresif, termasuk tombol tepi yang menempel di bawah dan dukungan untuk visual yang ditingkatkan: animasi Lottie, lebih banyak jenis gradien, dan gaya garis busur baru. - Catatan: beberapa fitur ini juga dapat digunakan tanpa bermigrasi ke API baru.

Rekomendasi

  • Migrasikan semua kartu Anda secara bersamaan. Hindari menggabungkan versi kartu dalam aplikasi Anda. Meskipun komponen Material 3 berada dalam artefak terpisah (androidx.wear.protolayout:protolayout-material3), sehingga secara teknis memungkinkan untuk menggunakan Kartu M2.5 dan M3 dalam aplikasi yang sama, sebaiknya hindari pendekatan ini kecuali jika benar-benar diperlukan (misalnya, jika aplikasi Anda memiliki sejumlah besar kartu yang tidak dapat dimigrasikan sekaligus).
  • Terapkan panduan UX Kartu. Mengingat sifat kartu yang sangat terstruktur dan berbasis template, gunakan desain dalam contoh yang ada sebagai titik awal untuk desain Anda sendiri.
  • Lakukan pengujian di berbagai ukuran layar dan font. Kartu sering kali berisi banyak informasi, sehingga teks (terutama saat ditempatkan pada tombol) rentan meluap dan terpotong. Untuk meminimalkan hal ini, gunakan komponen bawaan dan hindari penyesuaian yang ekstensif. Uji menggunakan fitur pratinjau kartu Android Studio serta di beberapa perangkat sungguhan.

Proses migrasi

Memperbarui dependensi

Pertama, perbarui file build.gradle.kts Anda. Perbarui versi dan ubah dependensi protolayout-material menjadi protolayout-material3, seperti yang ditunjukkan:

// In build.gradle.kts

//val tilesVersion = "1.4.1"
//val protoLayoutVersion = "1.2.1"

// Use these versions for M3.
val tilesVersion = "1.5.0-rc01"
val protoLayoutVersion = "1.3.0-rc01"

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

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

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

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

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

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

TileService sebagian besar tidak berubah

Perubahan utama dalam migrasi ini memengaruhi komponen UI. Oleh karena itu, penerapan TileService Anda, termasuk mekanisme pemuatan resource apa pun, seharusnya hanya memerlukan sedikit atau tidak memerlukan modifikasi.

Pengecualian utama melibatkan pelacakan aktivitas kartu: jika aplikasi Anda menggunakan onTileEnterEvent() atau onTileLeaveEvent(), Anda harus bermigrasi ke onRecentInteractionEventsAsync(). Mulai dari API 36, peristiwa ini akan dikelompokkan.

Menyesuaikan kode pembuatan tata letak

Di ProtoLayout 1.2 (M2.5), metode onTileRequest() menampilkan TileBuilders.Tile. Objek ini berisi berbagai elemen, termasuk TimelineBuilders.Timeline, yang pada gilirannya menyimpan LayoutElement yang mendeskripsikan UI kartu.

Dengan ProtoLayout 1.3 (M3), meskipun struktur dan alur data secara keseluruhan tidak berubah, LayoutElement kini dibuat menggunakan pendekatan yang terinspirasi dari Compose dengan tata letak berdasarkan slot yang ditentukan, yaitu (dari atas ke bawah) titleSlot (opsional; biasanya untuk judul atau header utama), mainSlot (wajib; untuk konten inti), dan bottomSlot (opsional; sering kali untuk tindakan seperti tombol tepi atau informasi tambahan seperti teks singkat). Tata letak ini dibuat oleh fungsi primaryLayout().

Tata letak kartu yang menampilkan mainSlot, titleSlot, bottomSlot
Gambar 1.: Slot kartu.
Perbandingan fungsi tata letak M2.5 dan M3

M2.5

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters
) =
    PrimaryLayout.Builder(deviceConfiguration)
        .setResponsiveContentInsetEnabled(true)
        .setContent(
            Text.Builder(context, "Hello World!")
                .setTypography(Typography.TYPOGRAPHY_BODY1)
                .setColor(argb(0xFFFFFFFF.toInt()))
                .build()
        )
        .build()

M3

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
) =
    materialScope(context, deviceConfiguration) {
        primaryLayout(mainSlot = { text("Hello, World!".layoutString) })
    }

Untuk menyoroti perbedaan utama:

  1. Penghapusan Jasa Konstruksi. Pola builder tradisional untuk komponen UI Material3 digantikan oleh sintaksis yang lebih deklaratif dan terinspirasi dari Compose. (Komponen non-UI seperti String/Color/Pengubah juga mendapatkan wrapper Kotlin baru.)
  2. Fungsi Tata Letak dan Inisialisasi Standar. Tata letak M3 mengandalkan fungsi inisialisasi dan struktur standar: materialScope() dan primaryLayout(). Fungsi wajib ini menginisialisasi lingkungan M3 (tema, cakupan komponen melalui materialScope) dan menentukan tata letak berbasis slot utama (melalui primaryLayout). Keduanya harus dipanggil tepat satu kali per tata letak.

Tema

Warna

Fitur unggulan Material 3 Ekspresif adalah "tema dinamis": kartu yang mengaktifkan fitur ini (aktif secara default) akan ditampilkan dalam tema yang disediakan sistem (ketersediaan bergantung pada perangkat dan konfigurasi pengguna).

Perubahan lain di M3 adalah perluasan jumlah token warna, yang telah meningkat dari 4 menjadi 29. Token warna baru dapat ditemukan di class ColorScheme.

Tipografi

Mirip dengan M2.5, M3 sangat mengandalkan konstanta ukuran font yang telah ditentukan sebelumnya—menentukan ukuran font secara langsung tidak disarankan. Konstanta ini berada di class Typography dan menawarkan rentang yang sedikit lebih luas untuk opsi yang lebih ekspresif.

Untuk mengetahui detail selengkapnya, lihat dokumentasi Tipografi.

Bentuk

Sebagian besar komponen M3 dapat bervariasi di sepanjang dimensi bentuk dan warna.

textButton (di mainSlot) dengan bentuk full:

Petak dengan bentuk 'penuh' (sudut lebih membulat)
Gambar 2.: Kotak dengan bentuk 'penuh'

textButton yang sama dengan bentuk small:

Petak dengan bentuk 'kecil' (sudut kurang bulat)
Gambar 3.: Kartu dengan bentuk 'kecil'

Komponen

Komponen M3 jauh lebih fleksibel dan dapat dikonfigurasi daripada komponen M2.5. Jika M2.5 sering kali memerlukan komponen yang berbeda untuk berbagai perlakuan visual, M3 sering kali menggunakan komponen "dasar" yang umum namun sangat dapat dikonfigurasi dengan default yang baik.

Prinsip ini berlaku untuk tata letak "root". Di M2.5, ini adalah PrimaryLayout atau EdgeContentLayout. Di M3, setelah MaterialScope tingkat teratas tunggal ditetapkan, fungsi primaryLayout() dipanggil. Hal ini akan menampilkan tata letak root secara langsung (tidak memerlukan builder) dan menerima LayoutElements untuk beberapa "slot", seperti titleSlot, mainSlot, dan bottomSlot. Slot ini dapat diisi dengan komponen UI konkret—seperti yang ditampilkan oleh text(), button(), atau card()—atau struktur tata letak, seperti Row atau Column dari LayoutElementBuilders.

Tema mewakili peningkatan utama M3 lainnya. Secara default, elemen UI otomatis mematuhi spesifikasi gaya M3 dan mendukung tema dinamis.

M2.5 M3
Elemen Interaktif
Button atau Chip
Teks
Text text()
Indikator Progres
CircularProgressIndicator circularProgressIndicator() atau segmentedCircularProgressIndicator()
Tata letak
PrimaryLayout atau EdgeContentLayout primaryLayout()
buttonGroup()
Gambar
icon(), avatarImage(), atau backgroundImage()

Pengubah

Di M3, Modifiers, yang Anda gunakan untuk mendekorasi atau menambah komponen, lebih mirip Compose. Perubahan ini dapat mengurangi boilerplate dengan membuat jenis internal yang sesuai secara otomatis. (Perubahan ini ortogonal terhadap penggunaan komponen UI M3; jika perlu, Anda dapat menggunakan pengubah gaya builder dari ProtoLayout 1.2 dengan komponen UI M3, dan sebaliknya.)

M2.5

// A Builder-style modifier to set the opacity of an element to 0.5
fun myModifier(): ModifiersBuilders.Modifiers =
    ModifiersBuilders.Modifiers.Builder()
        .setOpacity(TypeBuilders.FloatProp.Builder(0.5F).build())
        .build()

M3

// The equivalent Compose-like modifier is much simpler
fun myModifier(): LayoutModifier = LayoutModifier.opacity(0.5F)

Anda dapat membuat pengubah menggunakan gaya API, dan Anda juga dapat menggunakan fungsi ekstensi toProtoLayoutModifiers() untuk mengonversi LayoutModifier menjadi ModifiersBuilders.Modifier.

Fungsi Bantuan

Meskipun ProtoLayout 1.3 memungkinkan banyak komponen UI dinyatakan menggunakan API yang terinspirasi dari Compose, elemen tata letak dasar seperti baris dan kolom dari LayoutElementBuilders terus menggunakan pola builder. Untuk menjembatani kesenjangan gaya ini dan meningkatkan konsistensi dengan API komponen M3 baru, pertimbangkan untuk menggunakan fungsi helper.

Tanpa Pembantu

primaryLayout(
    mainSlot = {
        LayoutElementBuilders.Column.Builder()
            .setWidth(expand())
            .setHeight(expand())
            .addContent(text("A".layoutString))
            .addContent(text("B".layoutString))
            .addContent(text("C".layoutString))
            .build()
    }
)

Dengan Pembantu

// Function literal with receiver helper function
fun column(builder: Column.Builder.() -> Unit) =
    Column.Builder().apply(builder).build()

primaryLayout(
    mainSlot = {
        column {
            setWidth(expand())
            setHeight(expand())
            addContent(text("A".layoutString))
            addContent(text("B".layoutString))
            addContent(text("C".layoutString))
        }
    }
)

Bermigrasi ke Tiles 1.2 / ProtoLayout 1.0

Mulai versi 1.2, sebagian besar API tata letak Kartu berada di namespace androidx.wear.protolayout. Untuk menggunakan API terbaru, selesaikan langkah-langkah migrasi berikut dalam kode Anda.

Memperbarui dependensi

Dalam file build modul aplikasi Anda, buat perubahan berikut:

Groovy

  // Remove
  implementation 'androidx.wear.tiles:tiles-material:version'

  // Include additional dependencies
  implementation "androidx.wear.protolayout:protolayout:1.3.0"
  implementation "androidx.wear.protolayout:protolayout-material:1.3.0"
  implementation "androidx.wear.protolayout:protolayout-expression:1.3.0"

  // Update
  implementation "androidx.wear.tiles:tiles:1.5.0"

Kotlin

  // Remove
  implementation("androidx.wear.tiles:tiles-material:version")

  // Include additional dependencies
  implementation("androidx.wear.protolayout:protolayout:1.3.0")
  implementation("androidx.wear.protolayout:protolayout-material:1.3.0")
  implementation("androidx.wear.protolayout:protolayout-expression:1.3.0")

  // Update
  implementation("androidx.wear.tiles:tiles:1.5.0")

Memperbarui namespace

Di file kode berbasis Kotlin dan Java aplikasi Anda, lakukan pembaruan berikut. Atau, Anda dapat mengeksekusi skrip penggantian nama namespace ini.

  1. Ganti semua impor androidx.wear.tiles.material.* dengan androidx.wear.protolayout.material.*. Selesaikan juga langkah ini untuk library androidx.wear.tiles.material.layouts.
  2. Ganti sebagian besar impor androidx.wear.tiles.* lainnya dengan androidx.wear.protolayout.*.

    Impor untuk androidx.wear.tiles.EventBuilders, androidx.wear.tiles.RequestBuilders, androidx.wear.tiles.TileBuilders, dan androidx.wear.tiles.TileService harus tetap sama.

  3. Ganti nama beberapa metode yang tidak digunakan lagi dari class TileService dan TileBuilder:

    1. TileBuilders: getTimeline() ke getTileTimeline(), dan setTimeline() ke setTileTimeline()
    2. TileService: onResourcesRequest() ke onTileResourcesRequest()
    3. RequestBuilders.TileRequest: getDeviceParameters() ke getDeviceConfiguration(), setDeviceParameters() ke setDeviceConfiguration(), getState() ke getCurrentState(), dan setState() ke setCurrentState()