Sui dispositivi Wear OS, i riquadri vengono visualizzati da due componenti chiave con controllo delle versioni indipendente. Per assicurarti che i riquadri delle app funzionino correttamente su tutti i dispositivi, è importante comprendere questa architettura sottostante.
- Librerie correlate ai riquadri Jetpack: queste librerie (tra cui Wear Tiles
e Wear ProtoLayout) sono incorporate nella tua app e tu, in qualità di sviluppatore,
controlli le loro versioni. La tua app utilizza queste librerie per creare un oggetto
TileBuilder.Tile
(la struttura di dati che rappresenta il tuo riquadro) in risposta alla chiamataonTileRequest()
del sistema. - Renderer ProtoLayout:questo componente di sistema è responsabile del rendering
dell'oggetto
Tile
sul display e della gestione delle interazioni degli utenti. La versione del renderer non è controllata dallo sviluppatore dell'app e può variare a seconda dei dispositivi, anche di quelli con hardware identico.
L'aspetto o il comportamento di un riquadro può variare in base alle versioni della libreria Jetpack Tiles della tua app e alla versione del renderer ProtoLayout sul dispositivo dell'utente. Ad esempio, un dispositivo potrebbe supportare la rotazione o la visualizzazione dei dati sulla frequenza cardiaca, mentre un altro no.
Questo documento spiega come assicurarsi che l'app sia compatibile con diverse versioni della libreria Tiles e del renderer ProtoLayout e come eseguire la migrazione a versioni più recenti della libreria Jetpack.
Considera la compatibilità
Per creare un riquadro che funzioni correttamente su una vasta gamma di dispositivi, prendi in considerazione il supporto di varie funzionalità. Puoi farlo tramite due strategie principali: rilevare le funzionalità del renderer in fase di runtime e fornire fallback integrati.
Rilevare le funzionalità del renderer
Puoi modificare dinamicamente il layout del riquadro in base alle funzionalità disponibili su un determinato dispositivo.
Rilevare la versione del renderer
- Utilizza il metodo
getRendererSchemaVersion()
dell'oggettoDeviceParameters
passato al metodo onTileRequest(). Questo metodo restituisce i numeri di versione principale e secondaria del renderer ProtoLayout sul dispositivo. - Puoi quindi utilizzare la logica condizionale nell'implementazione di
onTileRequest()
per adattare il design o il comportamento del riquadro in base alla versione del renderer rilevata.
L'annotazione @RequiresSchemaVersion
- L'annotazione
@RequiresSchemaVersion
sui metodi ProtoLayout indica la versione minima dello schema del renderer richiesta per il funzionamento del metodo come documentato (esempio).- Sebbene la chiamata a un metodo che richiede una versione del renderer superiore a quella disponibile sul dispositivo non causi l'arresto anomalo dell'app, potrebbe comportare la mancata visualizzazione dei contenuti o l'ignoranza della funzionalità.
Esempio di rilevamento della versione
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() }
Fornire fallback
Alcune risorse ti consentono di definire un fallback direttamente nel builder. Questo è spesso più semplice rispetto al controllo della versione del renderer ed è l'approccio preferito quando disponibile.
Un caso d'uso comune è fornire un'immagine statica come fallback per un'animazione Lottie. Se il dispositivo non supporta le animazioni Lottie, verrà visualizzata l'immagine statica.
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()
Testare con versioni diverse del renderer
Per testare i tuoi riquadri con diverse versioni del renderer, implementali in versioni diverse dell'emulatore Wear OS. Sui dispositivi fisici, gli aggiornamenti di ProtoLayout Renderer vengono forniti dal Play Store o dagli aggiornamenti di sistema. Non è possibile forzare l'installazione di una versione specifica del renderer.
La funzionalità di anteprima dei riquadri di Android Studio utilizza un renderer incorporato nella libreria Jetpack ProtoLayout da cui dipende il tuo codice, quindi un altro approccio consiste nel dipendere da versioni diverse della libreria Jetpack durante il test dei riquadri.
Esegui la migrazione a Tiles 1.5 / ProtoLayout 1.3 (Material 3 Expressive)
Aggiorna le librerie Jetpack Tile per sfruttare i miglioramenti più recenti, incluse le modifiche all'interfaccia utente per integrare perfettamente i tuoi riquadri con il sistema.
Jetpack Tiles 1.5 e Jetpack ProtoLayout 1.3 introducono diversi miglioramenti e modifiche significativi. come le seguenti.
- Un'API simile a Compose per descrivere la UI.
- Componenti Material 3 Expressive, tra cui il pulsante che aderisce al bordo inferiore e il supporto per elementi visivi migliorati: animazioni Lottie, più tipi di sfumature e nuovi stili di linee ad arco. - Nota: alcune di queste funzionalità possono essere utilizzate anche senza eseguire la migrazione alla nuova API.
Consigli
- Esegui la migrazione di tutte le tessere contemporaneamente. Evita di combinare le versioni dei riquadri
all'interno della tua app. Anche se i componenti Material 3 si trovano in un artefatto
separato (
androidx.wear.protolayout:protolayout-material3
), il che rende tecnicamente possibile utilizzare sia i riquadri M2.5 che M3 nella stessa app, sconsigliamo vivamente questo approccio, a meno che non sia assolutamente necessario (ad esempio, se la tua app ha un numero elevato di riquadri che non possono essere migrati tutti contemporaneamente). - Adotta le linee guida per l'esperienza utente dei riquadri. Data la natura altamente strutturata e basata su modelli dei riquadri, utilizza i design negli esempi esistenti come punto di partenza per i tuoi design.
- Esegui test su una varietà di dimensioni dello schermo e del carattere. I riquadri sono spesso ricchi di informazioni, il che rende il testo (soprattutto se posizionato sui pulsanti) suscettibile a overflow e troncamento. Per ridurre al minimo questo problema, utilizza i componenti predefiniti ed evita personalizzazioni eccessive. Esegui test utilizzando la funzionalità di anteprima dei riquadri di Android Studio e su più dispositivi reali.
Processo di migrazione
Aggiorna le dipendenze
Innanzitutto, aggiorna il file build.gradle.kts
. Aggiorna le versioni e modifica la dipendenza
protolayout-material
in protolayout-material3
, come mostrato di seguito:
// 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 rimane in gran parte invariato
Le modifiche principali di questa migrazione riguardano i componenti della UI. Di conseguenza, l'implementazione di TileService
, inclusi eventuali meccanismi di caricamento delle risorse, dovrebbe richiedere modifiche minime o nulle.
L'eccezione principale riguarda il monitoraggio dell'attività dei riquadri: se la tua app utilizza
onTileEnterEvent()
o onTileLeaveEvent()
, devi eseguire la migrazione a
onRecentInteractionEventsAsync()
. A partire dall'API 36, questi eventi
verranno raggruppati in batch.
Adattare il codice di generazione del layout
In ProtoLayout 1.2 (M2.5), il metodo onTileRequest()
restituisce un
TileBuilders.Tile
. Questo oggetto conteneva vari elementi, tra cui un
TimelineBuilders.Timeline
, che a sua volta conteneva il LayoutElement
che descrive l'interfaccia utente del riquadro.
Con ProtoLayout 1.3 (M3), la struttura e il flusso complessivi dei dati non sono cambiati, ma LayoutElement
ora viene creato utilizzando un approccio ispirato a Compose con un layout basato su slot definiti che sono (dall'alto verso il basso) titleSlot
(facoltativo; in genere per un titolo o un'intestazione principale), mainSlot
(obbligatorio; per i contenuti principali) e bottomSlot
(facoltativo; spesso per azioni come un pulsante laterale o informazioni supplementari come un breve testo). Questo layout è
costruito dalla funzione primaryLayout()
.

Confronto tra le funzioni di layout M2.5 e 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) })
}
Per evidenziare le differenze principali:
- Eliminazione di costruttori. Il pattern di builder tradizionale per i componenti UI Material3 viene sostituito da una sintassi più dichiarativa e ispirata a Compose. (Anche i componenti non UI come String/Color/Modifiers ricevono nuovi wrapper Kotlin.)
- Funzioni di inizializzazione e layout standardizzate. I layout M3 si basano su
funzioni di inizializzazione e struttura standardizzate:
materialScope()
eprimaryLayout()
. Queste funzioni obbligatorie inizializzano l'ambiente M3 (temi, ambito dei componenti tramitematerialScope
) e definiscono il layout principale basato sugli slot (tramiteprimaryLayout
). Entrambe devono essere chiamate esattamente una volta per layout.
Applicazione tema
Colore
Una delle caratteristiche più importanti di Material 3 Expressive è la "tematizzazione dinamica": i riquadri che attivano questa funzionalità (attiva per impostazione predefinita) vengono visualizzati nel tema fornito dal sistema (la disponibilità dipende dal dispositivo e dalla configurazione dell'utente).
Un altro cambiamento in M3 è l'espansione del numero di token di colore, che è
aumentato da 4 a 29. I nuovi token di colore si trovano nella classe
ColorScheme
.
Tipografia
Simile a M2.5, M3 si basa in gran parte su costanti di dimensione del carattere predefinite. È sconsigliato specificare direttamente una dimensione del carattere. Queste costanti si trovano nella classe
Typography
e offrono una gamma leggermente più ampia di opzioni
più espressive.
Per tutti i dettagli, consulta la documentazione sulla tipografia.
Forma
La maggior parte dei componenti M3 può variare in base alla forma e al colore.
Un textButton
(in mainSlot
) con forma full
:

Lo stesso pulsante di testo con forma small
:

Componenti
I componenti M3 sono molto più flessibili e configurabili rispetto alle loro controparti M2.5. Mentre M2.5 spesso richiedeva componenti distinti per trattamenti visivi diversi, M3 utilizza spesso un componente "base" generalizzato ma altamente configurabile con valori predefiniti validi.
Questo principio si applica al layout "root". Nella versione M2.5, si trattava di un
PrimaryLayout
o di un EdgeContentLayout
. In M3, dopo aver stabilito un singolo
MaterialScope
di primo livello, viene chiamata la funzione primaryLayout()
. Restituisce direttamente il layout principale (non sono necessari builder) e accetta LayoutElements
per diversi "slot", ad esempio titleSlot
, mainSlot
e bottomSlot
. Questi slot possono essere compilati con componenti UI concreti, ad esempio quelli restituiti da text(), button() o card(), oppure con strutture di layout, come Row
o Column
da LayoutElementBuilders
.
I temi rappresentano un altro miglioramento chiave di M3. Per impostazione predefinita, gli elementi dell'interfaccia utente rispettano automaticamente le specifiche di stile M3 e supportano i temi dinamici.
M2.5 | M3 |
---|---|
Elementi interattivi | |
Button o Chip |
|
Testo | |
Text |
text() |
Indicatori di avanzamento | |
CircularProgressIndicator |
circularProgressIndicator() o segmentedCircularProgressIndicator() |
Layout | |
PrimaryLayout o EdgeContentLayout |
primaryLayout() |
— | buttonGroup() |
Immagini | |
— | icon() , avatarImage() o backgroundImage() |
Modificatori
In M3, Modifiers
, che utilizzi per decorare o aumentare un componente, sono
più simili a Compose. Questa modifica può ridurre il boilerplate costruendo automaticamente
i tipi interni appropriati. Questa modifica è ortogonale all'utilizzo dei componenti UI M3; se necessario, puoi utilizzare i modificatori in stile builder di ProtoLayout 1.2 con i componenti UI M3 e viceversa.
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)
Puoi creare modificatori utilizzando lo stile API e puoi anche utilizzare la funzione di estensione
toProtoLayoutModifiers()
per convertire un
LayoutModifier
in un ModifiersBuilders.Modifier
.
Funzioni helper
Sebbene ProtoLayout 1.3 consenta di esprimere molti componenti dell'interfaccia utente utilizzando un'API ispirata a Compose, gli elementi di layout di base come righe e colonne di LayoutElementBuilders
continuano a utilizzare il pattern builder. Per colmare questo divario stilistico e promuovere la coerenza con le nuove API dei componenti M3, valuta la possibilità di utilizzare le funzioni helper.
Senza helper
primaryLayout(
mainSlot = {
LayoutElementBuilders.Column.Builder()
.setWidth(expand())
.setHeight(expand())
.addContent(text("A".layoutString))
.addContent(text("B".layoutString))
.addContent(text("C".layoutString))
.build()
}
)
Con assistenti
// 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))
}
}
)
Esegui la migrazione a Tiles 1.2 / ProtoLayout 1.0
A partire dalla versione 1.2, la maggior parte delle API di layout delle schede si trova nello spazio dei nomi androidx.wear.protolayout
. Per utilizzare le API più recenti, completa i seguenti passaggi di migrazione nel tuo codice.
Aggiorna le dipendenze
Nel file di build del modulo dell'app, apporta le seguenti modifiche:
Trendy
// 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")
Aggiorna spazi dei nomi
Nei file di codice basati su Kotlin e Java della tua app, apporta i seguenti aggiornamenti. In alternativa, puoi eseguire questo script di ridenominazione dello spazio dei nomi.
- Sostituisci tutte le importazioni di
androidx.wear.tiles.material.*
conandroidx.wear.protolayout.material.*
. Completa questo passaggio anche per la libreriaandroidx.wear.tiles.material.layouts
. Sostituisci la maggior parte delle altre importazioni di
androidx.wear.tiles.*
conandroidx.wear.protolayout.*
.Le importazioni per
androidx.wear.tiles.EventBuilders
,androidx.wear.tiles.RequestBuilders
,androidx.wear.tiles.TileBuilders
eandroidx.wear.tiles.TileService
devono rimanere invariate.Rinomina alcuni metodi ritirati dalle classi TileService e TileBuilder:
TileBuilders
: dagetTimeline()
agetTileTimeline()
e dasetTimeline()
asetTileTimeline()
TileService
: daonResourcesRequest()
aonTileResourcesRequest()
RequestBuilders.TileRequest
:getDeviceParameters()
agetDeviceConfiguration()
,setDeviceParameters()
asetDeviceConfiguration()
,getState()
agetCurrentState()
esetState()
asetCurrentState()