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 panggilanonTileRequest()
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 objekDeviceParameters
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()
.

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:
- 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.)
- Fungsi Tata Letak dan Inisialisasi Standar. Tata letak M3 mengandalkan fungsi inisialisasi dan struktur standar:
materialScope()
danprimaryLayout()
. Fungsi wajib ini menginisialisasi lingkungan M3 (tema, cakupan komponen melaluimaterialScope
) dan menentukan tata letak berbasis slot utama (melaluiprimaryLayout
). 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
:

textButton yang sama dengan bentuk small
:

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
// Removeimplementation '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
// Removeimplementation("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.
- Ganti semua impor
androidx.wear.tiles.material.*
denganandroidx.wear.protolayout.material.*
. Selesaikan juga langkah ini untuk libraryandroidx.wear.tiles.material.layouts
. Ganti sebagian besar impor
androidx.wear.tiles.*
lainnya denganandroidx.wear.protolayout.*
.Impor untuk
androidx.wear.tiles.EventBuilders
,androidx.wear.tiles.RequestBuilders
,androidx.wear.tiles.TileBuilders
, danandroidx.wear.tiles.TileService
harus tetap sama.Ganti nama beberapa metode yang tidak digunakan lagi dari class TileService dan TileBuilder:
TileBuilders
:getTimeline()
kegetTileTimeline()
, dansetTimeline()
kesetTileTimeline()
TileService
:onResourcesRequest()
keonTileResourcesRequest()
RequestBuilders.TileRequest
:getDeviceParameters()
kegetDeviceConfiguration()
,setDeviceParameters()
kesetDeviceConfiguration()
,getState()
kegetCurrentState()
, dansetState()
kesetCurrentState()