Sui dispositivi Wear OS, i riquadri vengono visualizzati da due componenti chiave con versionamento indipendente. Per assicurarti che i riquadri delle app funzionino correttamente su tutti i dispositivi, è importante comprendere questa architettura di base.
- Librerie relative ai riquadri di Jetpack: queste librerie (inclusi Wear Tiles
e Wear ProtoLayout) sono incorporate nella tua app e tu, in qualità di sviluppatore,
controlli le relative versioni. L'app utilizza queste librerie per creare un oggetto
TileBuilder.Tile
(la struttura di dati che rappresenta il riquadro) in risposta alla chiamataonTileRequest()
del sistema. - ProtoLayout Renderer:questo componente di sistema è responsabile del rendering dell'oggetto
Tile
sul display e della gestione delle interazioni degli utenti. La versione del visualizzatore non è controllata dallo sviluppatore dell'app e può variare da un dispositivo all'altro, anche se hanno hardware identico.
L'aspetto o il comportamento di una scheda 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 potrebbe non farlo.
Questo documento spiega come assicurarti che la tua app sia compatibile con le diverse versioni della libreria Tiles e del Renderer ProtoLayout e come eseguire la migrazione a versioni più recenti della libreria Jetpack.
Prendi in considerazione la compatibilità
Per creare un riquadro che funzioni correttamente su una serie di dispositivi, devi tenere conto di quanto segue.
Rileva la versione del renderer
- Utilizza il metodo
getRendererSchemaVersion()
dell'oggettoDeviceParameters
passato al metodo onTileRequest(). Questo metodo restituisce i numeri di versione maggiore e minore di ProtoLayout Renderer 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 visualizzatore rilevata.- Ad esempio, se un'animazione specifica non è supportata, puoi visualizzare un'immagine statica.
L'annotazione @RequiresSchemaVersion
- L'annotazione
@RequiresSchemaVersion
sui metodi ProtoLayout indica la versione minima dello schema del renderer richiesta per il comportamento del metodo come documentato (esempio).- L'utilizzo di un metodo che richiede una versione del renderer superiore a quella disponibile sul dispositivo non causerà l'arresto anomalo dell'app, ma potrebbe comportare la mancata visualizzazione dei contenuti o l'ignoranza della funzionalità.
Esempio
override fun onTileRequest(
requestParams: TileService.TileRequest
): ListenableFuture<Tile> {
val rendererVersion =
requestParams.deviceConfiguration.rendererSchemaVersion
val tile = Tile.Builder()
if (
rendererVersion.major > 1 ||
(rendererVersion.major == 1 && rendererVersion.minor >= 300)
) {
// Use a feature supported in renderer version 1.300 or later
tile.setTileTimeline(/* ... */ )
} else {
// Provide fallback content for older renderers
tile.setTileTimeline(/* ... */ )
}
return Futures.immediateFuture(tile.build())
}
Esegui test con versioni diverse del renderer
Per testare i riquadri con versioni diverse del renderer, esegui il deployment 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à Anteprima riquadri di Android Studio utilizza un visualizzatore incorporato nella libreria Jetpack ProtoLayout da cui dipende il codice, quindi un altro approccio è fare affidamento su 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 usufruire dei più recenti miglioramenti, tra cui le modifiche all'interfaccia utente per integrare perfettamente i 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 l'interfaccia utente.
- Componenti Material 3 Expressive, tra cui il pulsante con bordo che avvolge la parte inferiore e il supporto di immagini migliorate: animazioni Lottie, più tipi di gradiente e nuovi stili di linee curve. - Nota: alcune di queste funzionalità possono essere utilizzate anche senza eseguire la migrazione alla nuova API.
Consigli
- Esegui la migrazione di tutti i riquadri contemporaneamente. Evita di mescolare le versioni dei riquadri
all'interno della tua app. Sebbene i componenti di Material 3 risiedano in un
elemento distinto (
androidx.wear.protolayout:protolayout-material3
), il che consente tecnicamente di utilizzare sia i riquadri M2.5 che quelli M3 nella stessa app, consigliamo vivamente di non adottare questo approccio, a meno che non sia assolutamente necessario (per esempio, se la tua app ha un numero elevato di riquadri di cui non è possibile eseguire la migrazione contemporaneamente). - Adotta le linee guida per l'esperienza utente di riquadri. Data la natura altamente strutturata e basata su modelli dei riquadri, utilizza i progetti negli esempi esistenti come punto di partenza per i tuoi progetti.
- Esegui test su una varietà di schermi e dimensioni dei caratteri. Le schede spesso contengono molte informazioni, il che rende il testo (soprattutto se posizionato sui pulsanti) soggetto a overflow e ritaglio. Per ridurlo al minimo, utilizza i componenti predefiniti ed evita personalizzazioni eccessive. Esegui il test utilizzando la funzionalità di anteprima delle schede 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 dell'interfaccia utente. 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 delle 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.
Adatta 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 l'LayoutElement
che descrive l'interfaccia utente del riquadro.
Con ProtoLayout 1.3 (M3), anche se la struttura e il flusso dei dati complessivi non sono stati modificati, il LayoutElement
viene ora costruito utilizzando un approccio ispirato a Compose con un layout basato su slot definiti che sono (dall'alto verso il basso) il titleSlot
(in genere per un titolo o un'intestazione principale), il mainSlot
(per i contenuti principali) e il bottomSlot
(spesso per azioni come un pulsante laterale o informazioni aggiuntive come un testo breve). Questo layout viene creato dalla funzione
primaryLayout()
.

Confronto delle 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 degli sviluppatori. Il pattern di builder tradizionale per i componenti UI di Material3 viene sostituito da una sintassi più dichiarativa 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 (tema, ambito del componente tramitematerialScope
) e definiscono il layout principale basato su slot (tramiteprimaryLayout
). Entrambe devono essere chiamate esattamente una volta per layout.
Applicazione tema
Colore
Una funzionalità di spicco di Material 3 Expressive è la "tecnologia di temi dinamici": i riquadri che attivano questa funzionalità (attiva per impostazione predefinita) verranno visualizzati nel tema fornito dal sistema (la disponibilità dipende dal dispositivo e dalla configurazione dell'utente).
Un'altra modifica in M3 è l'espansione del numero di token di colore, che è aumentato da 4 a 29. I nuovi token di colore sono disponibili nella classe
ColorScheme
.
Caratteri
Come M2.5, M3 si basa molto sulle costanti delle dimensioni dei caratteri predefinite. Si sconsiglia di 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 relativa alla tipografia.
Forma
La maggior parte dei componenti M3 può variare in termini di forma e 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 ai loro omologhi M2.5. Mentre M2.5 spesso richiedeva componenti distinti per diversi trattamenti visivi, M3 utilizza spesso un componente "base" generalizzato, ma altamente configurabile, con valori predefiniti efficaci.
Questo principio si applica al layout "root". In M2.5, era un
PrimaryLayout
o 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", come titleSlot
, mainSlot
e bottomSlot
. Questi slot possono essere compilati con componenti UI specifici, come quelli restituiti da text(), button() o card(), oppure con strutture di layout, come Row
o Column
di LayoutElementBuilders
.
I temi rappresentano un altro importante miglioramento di M3. Per impostazione predefinita, gli elementi dell'interfaccia utente si conformano automaticamente alle specifiche di stile di 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 codice boilerplate costruendo automaticamente i tipi interni appropriati. Questa modifica è ortogonale all'utilizzo dei componenti dell'interfaccia utente di M3. Se necessario, puoi utilizzare i modificatori in stile builder di ProtoLayout 1.2 con i componenti dell'interfaccia utente di 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 entrambi gli stili API e puoi anche utilizzare la funzione di estensione toProtoLayoutModifiers()
per convertire un LayoutModifier
in un ModifiersBuilders.Modifier
.
Funzioni di supporto
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 rows e
columns di LayoutElementBuilders
continuano a utilizzare il pattern
del costruttore. Per colmare questa differenza stilistica e promuovere la coerenza con le nuove API dei componenti M3, ti consigliamo di utilizzare le funzioni di supporto.
Senza assistenti
primaryLayout(
mainSlot = {
LayoutElementBuilders.Column.Builder()
.setWidth(expand())
.setHeight(expand())
.addContent(text("A".layoutString))
.addContent(text("B".layoutString))
.addContent(text("C".layoutString))
.build()
}
)
Con collaboratori
// 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))
}
}
)
Eseguire la migrazione a Tiles 1.2 / ProtoLayout 1.0
A partire dalla versione 1.2, la maggior parte delle API di layout delle riquadri 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:
Groovy
// Removeimplementation 'androidx.wear.tiles:tiles-material:version'// Include additional dependencies implementation "androidx.wear.protolayout:protolayout:1.2.1" implementation "androidx.wear.protolayout:protolayout-material:1.2.1" implementation "androidx.wear.protolayout:protolayout-expression:1.2.1" // Update implementation "androidx.wear.tiles:tiles:1.4.1"
Kotlin
// Removeimplementation("androidx.wear.tiles:tiles-material:version")// Include additional dependencies implementation("androidx.wear.protolayout:protolayout:1.2.1") implementation("androidx.wear.protolayout:protolayout-material:1.2.1") implementation("androidx.wear.protolayout:protolayout-expression:1.2.1") // Update implementation("androidx.wear.tiles:tiles:1.4.1")
Aggiorna gli spazi dei nomi
Apporta i seguenti aggiornamenti ai file di codice basati su Kotlin e Java della tua app. In alternativa, puoi eseguire questo script di rinominazione dello spazio dei nomi.
- Sostituisci tutte le importazioni di
androidx.wear.tiles.material.*
conandroidx.wear.protolayout.material.*
. Completa questo passaggio anche per la bibliotecaandroidx.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
dovrebbero rimanere invariate.Rinomina alcuni metodi deprecati delle classi TileService e TileBuilder:
TileBuilders
: dagetTimeline()
agetTileTimeline()
e dasetTimeline()
asetTileTimeline()
TileService
: daonResourcesRequest()
aonTileResourcesRequest()
RequestBuilders.TileRequest
: dagetDeviceParameters()
agetDeviceConfiguration()
, dasetDeviceParameters()
asetDeviceConfiguration()
, dagetState()
agetCurrentState()
e dasetState()
asetCurrentState()