Auf Wear OS-Geräten werden Kacheln von zwei Hauptkomponenten mit unabhängiger Versionierung gerendert. Damit die App-Kacheln auf allen Geräten ordnungsgemäß funktionieren, ist es wichtig, diese zugrunde liegende Architektur zu verstehen.
- Jetpack-Bibliotheken für Ansichten: Diese Bibliotheken (einschließlich Wear Tiles und Wear ProtoLayout) sind in Ihre App eingebettet und Sie als Entwickler steuern ihre Versionen. Ihre App verwendet diese Bibliotheken, um als Reaktion auf den
onTileRequest()
-Aufruf des Systems einTileBuilder.Tile
-Objekt (die Datenstruktur, die Ihre Kachel darstellt) zu erstellen. - ProtoLayout-Renderer:Diese Systemkomponente ist für das Rendern des
Tile
-Objekts auf dem Display und für die Verarbeitung von Nutzerinteraktionen verantwortlich. Die Version des Renderers wird nicht vom App-Entwickler gesteuert und kann von Gerät zu Gerät variieren, auch bei identischer Hardware.
Das Aussehen oder Verhalten einer Kachel kann sowohl von den Bibliotheksversionen von Jetpack Tiles in Ihrer App als auch von der ProtoLayout-Renderer-Version auf dem Gerät des Nutzers abhängen. So kann ein Gerät beispielsweise die Drehung oder die Anzeige von Herzfrequenzdaten unterstützen, ein anderes Gerät aber nicht.
In diesem Dokument wird beschrieben, wie Sie dafür sorgen, dass Ihre App mit verschiedenen Versionen der Tiles-Bibliothek und des ProtoLayout-Renderers kompatibel ist, und wie Sie zu höheren Versionen der Jetpack-Bibliothek migrieren.
Kompatibilität berücksichtigen
Wenn Sie eine Kachel erstellen möchten, die auf verschiedenen Geräten ordnungsgemäß funktioniert, sollten Sie Folgendes beachten:
Rendererversion erkennen
- Verwenden Sie die Methode
getRendererSchemaVersion()
desDeviceParameters
-Objekts, das an die Methode onTileRequest() übergeben wird. Diese Methode gibt die Haupt- und Nebenversionsnummern des ProtoLayout-Renderers auf dem Gerät zurück. - Sie können dann in Ihrer
onTileRequest()
-Implementierung bedingte Logik verwenden, um das Design oder Verhalten der Kachel basierend auf der erkannten Rendererversion anzupassen.- Wenn eine bestimmte Animation beispielsweise nicht unterstützt wird, können Sie stattdessen ein statisches Bild anzeigen.
Die @RequiresSchemaVersion
-Anmerkung
- Die
@RequiresSchemaVersion
-Anmerkung bei ProtoLayout-Methoden gibt die Mindestversion des Renderer-Schemas an, die erforderlich ist, damit sich diese Methode wie beschrieben verhält (Beispiel).- Wenn Sie eine Methode aufrufen, für die eine höhere Rendererversion erforderlich ist als auf dem Gerät verfügbar ist, stürzt Ihre App zwar nicht ab, aber es kann dazu führen, dass Inhalte nicht angezeigt oder die Funktion ignoriert wird.
Beispiel
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())
}
Mit verschiedenen Rendererversionen testen
Wenn Sie Ihre Ansichten mit verschiedenen Rendererversionen testen möchten, müssen Sie sie in verschiedenen Versionen des Wear OS-Emulators bereitstellen. Auf physischen Geräten werden ProtoLayout-Renderer-Updates über den Play Store oder Systemupdates bereitgestellt. Es ist nicht möglich, die Installation einer bestimmten Rendererversion zu erzwingen.)
Die Funktion „Vorschau für Ansichten“ in Android Studio verwendet einen Renderer, der in der Jetpack ProtoLayout-Bibliothek eingebettet ist, von der Ihr Code abhängt. Ein anderer Ansatz besteht darin, beim Testen von Ansichten verschiedene Jetpack-Bibliotheksversionen zu verwenden.
Zu Tiles 1.5 / ProtoLayout 1.3 (Material 3 Expressive) migrieren
Aktualisieren Sie Ihre Jetpack Tile-Bibliotheken, um die neuesten Verbesserungen zu nutzen, einschließlich UI-Änderungen, damit sich Ihre Kacheln nahtlos in das System einbinden lassen.
Jetpack Tiles 1.5 und Jetpack ProtoLayout 1.3 bieten mehrere wichtige Verbesserungen und Änderungen. Dazu gehören:
- Eine Compose-ähnliche API zum Beschreiben der Benutzeroberfläche.
- Material 3 Expressive-Komponenten, einschließlich der Schaltfläche mit abgerundeten Ecken und Unterstützung für erweiterte visuelle Elemente: Lottie-Animationen, mehr Farbverlaufstypen und neue Bogenlinienstile. – Hinweis: Einige dieser Funktionen können auch ohne Migration zur neuen API verwendet werden.
Empfehlungen
- Alle Kacheln gleichzeitig migrieren Verwenden Sie in Ihrer App keine unterschiedlichen Ansichten. Die Material 3-Komponenten befinden sich zwar in einem separaten Artefakt (
androidx.wear.protolayout:protolayout-material3
), sodass es technisch möglich ist, sowohl M2.5- als auch M3-Kacheln in derselben App zu verwenden. Wir raten jedoch dringend davon ab, es sei denn, dies ist absolut notwendig, z. B. wenn Ihre App eine große Anzahl von Kacheln enthält, die nicht alle gleichzeitig migriert werden können. - Befolgen Sie die UX-Richtlinien für Ansichten mit Kacheln. Da Kacheln sehr strukturiert und vorlagenbasiert sind, können Sie die Designs in den vorhandenen Beispielen als Ausgangspunkt für Ihre eigenen Designs verwenden.
- Testen Sie auf verschiedenen Bildschirmen und mit verschiedenen Schriftgrößen. Da sie oft viele Informationen enthalten, ist der Text (insbesondere auf Schaltflächen) anfällig für Überlauf und Ausschneiden. Verwenden Sie die vordefinierten Komponenten und vermeiden Sie umfangreiche Anpassungen, um dies zu minimieren. Testen Sie die Funktion mit der Vorschau für Ansichten in Android Studio und auf mehreren echten Geräten.
Migrationsprozess
Abhängigkeiten aktualisieren
Aktualisieren Sie zuerst die Datei build.gradle.kts
. Aktualisieren Sie die Versionen und ändern Sie die Abhängigkeit von protolayout-material
zu protolayout-material3
, wie hier gezeigt:
// 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 bleibt weitgehend unverändert
Die wichtigsten Änderungen bei dieser Migration betreffen die UI-Komponenten. Daher sollten für Ihre TileService
-Implementierung, einschließlich aller Mechanismen zum Laden von Ressourcen, nur minimale oder gar keine Änderungen erforderlich sein.
Die Hauptausnahme betrifft das Erfassen von Kachelnaktivitäten: Wenn in Ihrer App onTileEnterEvent()
oder onTileLeaveEvent()
verwendet wird, sollten Sie zu onRecentInteractionEventsAsync()
migrieren. Ab API 36 werden diese Ereignisse in Batches gesendet.
Code zur Layoutgenerierung anpassen
In ProtoLayout 1.2 (M2.5) gibt die Methode onTileRequest()
einen TileBuilders.Tile
zurück. Dieses Objekt enthielt verschiedene Elemente, darunter ein TimelineBuilders.Timeline
, das wiederum das LayoutElement
enthielt, das die Benutzeroberfläche der Kachel beschreibt.
Bei ProtoLayout 1.3 (M3) haben sich die Datenstruktur und der Fluss insgesamt nicht geändert. Die LayoutElement
wird jetzt jedoch mit einem von Compose inspirierten Ansatz mit einem Layout erstellt, das auf definierten Slots basiert. Das sind (von oben nach unten) titleSlot
(in der Regel für einen Haupttitel oder Header), mainSlot
(für den Hauptinhalt) und bottomSlot
(häufig für Aktionen wie eine seitliche Schaltfläche oder ergänzende Informationen wie kurzer Text). Dieses Layout wird mit der Funktion primaryLayout()
erstellt.

Vergleich der Layoutfunktionen M2.5 und 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) })
}
So heben Sie die wichtigsten Unterschiede hervor:
- Entfernung von Buildern Das traditionelle Builder-Muster für Material3-UI-Komponenten wird durch eine deklarativere, von Compose inspirierte Syntax ersetzt. Auch nicht zur Benutzeroberfläche gehörende Komponenten wie String/Color/Modifier erhalten neue Kotlin-Wrapper.
- Standardisierte Initialisierungs- und Layoutfunktionen M3-Layouts basieren auf standardisierten Initialisierungs- und Strukturfunktionen:
materialScope()
undprimaryLayout()
. Diese obligatorischen Funktionen initialisieren die M3-Umgebung (Design, Komponentenbereich übermaterialScope
) und definieren das primäre slottingbasierte Layout (überprimaryLayout
). Beide müssen genau einmal pro Layout aufgerufen werden.
Designs
Farbe
Ein herausragendes Merkmal von Material 3 Expressive ist das „dynamische Design“. Kacheln, die diese Funktion aktivieren (standardmäßig aktiviert), werden im vom System bereitgestellten Design angezeigt. Die Verfügbarkeit hängt vom Gerät und der Konfiguration des Nutzers ab.
Eine weitere Änderung in M3 ist die Ausweitung der Anzahl der Farb-Token, die von 4 auf 29 erhöht wurde. Die neuen Farb-Tokens finden Sie in der Klasse ColorScheme
.
Typografie
Ähnlich wie bei M2.5 werden in M3 vordefinierte Schriftgrößenkonstanten verwendet. Die direkte Angabe einer Schriftgröße wird nicht empfohlen. Diese Konstanten befinden sich in der Klasse Typography
und bieten eine etwas erweiterte Auswahl an ausdrucksstärkeren Optionen.
Ausführliche Informationen finden Sie in der Dokumentation zur Typografie.
Form
Die meisten M3-Komponenten können sowohl in Form als auch in Farbe variieren.
Eine textButton
(in der mainSlot
) mit der Form full
:

Dieselbe Textschaltfläche mit der Form small
:

Komponenten
M3-Komponenten sind deutlich flexibler und konfigurierbarer als ihre M2.5-Äquivalente. Während für M2.5 oft unterschiedliche Komponenten für verschiedene visuelle Darstellungen erforderlich waren, wird in M3 häufig eine generalisierte, aber hochgradig konfigurierbare „Basis“-Komponente mit guten Standardeinstellungen verwendet.
Dieses Prinzip gilt für das „Stamm“-Layout. In M2.5 war dies entweder ein PrimaryLayout
oder ein EdgeContentLayout
. In M3 wird nach dem Erstellen einer einzelnen MaterialScope
der obersten Ebene die Funktion primaryLayout()
aufgerufen. Dadurch wird das Stammlayout direkt zurückgegeben (keine Builder erforderlich) und LayoutElements
wird für mehrere „Slots“ akzeptiert, z. B. titleSlot
, mainSlot
und bottomSlot
. Diese Slots können mit bestimmten UI-Komponenten wie text(), button() oder card() oder Layoutstrukturen wie Row
oder Column
aus LayoutElementBuilders
ausgefüllt werden.
Eine weitere wichtige M3-Erweiterung sind Themen. Standardmäßig entsprechen UI-Elemente automatisch den M3-Stilvorgaben und unterstützen dynamische Designs.
M2.5 | M3 |
---|---|
Interaktive Elemente | |
Button oder Chip |
|
Text | |
Text |
text() |
Fortschrittsanzeigen | |
CircularProgressIndicator |
circularProgressIndicator() oder segmentedCircularProgressIndicator() |
Layout | |
PrimaryLayout oder EdgeContentLayout |
primaryLayout() |
– | buttonGroup() |
Bilder | |
– | icon() , avatarImage() oder backgroundImage() |
Modifikatoren
In M3 sind Modifiers
, mit denen Sie eine Komponente verzieren oder ergänzen, eher mit Compose vergleichbar. Durch diese Änderung kann Boilerplate reduziert werden, da die entsprechenden internen Typen automatisch erstellt werden. Diese Änderung ist unabhängig von der Verwendung von M3-UI-Komponenten. Bei Bedarf können Sie Builder-Modifizierer aus ProtoLayout 1.2 mit M3-UI-Komponenten und umgekehrt verwenden.
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)
Sie können Modifikatoren mit beiden API-Stilen erstellen und auch die Erweiterungsfunktion toProtoLayoutModifiers()
verwenden, um ein LayoutModifier
in ein ModifiersBuilders.Modifier
umzuwandeln.
Hilfsfunktionen
Mit ProtoLayout 1.3 können viele UI-Komponenten mit einer von Compose inspirierten API ausgedrückt werden. Für grundlegende Layoutelemente wie Zeilen und Spalten aus LayoutElementBuilders
wird weiterhin das Builder-Muster verwendet. Um diese stilistische Lücke zu schließen und für Einheitlichkeit mit den neuen M3-Komponenten-APIs zu sorgen, sollten Sie Hilfsfunktionen verwenden.
Ohne Helfer
primaryLayout(
mainSlot = {
LayoutElementBuilders.Column.Builder()
.setWidth(expand())
.setHeight(expand())
.addContent(text("A".layoutString))
.addContent(text("B".layoutString))
.addContent(text("C".layoutString))
.build()
}
)
Mit Helfern
// 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))
}
}
)
Zu Ansichten 1.2 / ProtoLayout 1.0 migrieren
Ab Version 1.2 befinden sich die meisten APIs für das Layout von Ansichten im Namespace androidx.wear.protolayout
. Wenn Sie die neuesten APIs verwenden möchten, führen Sie die folgenden Migrationsschritte in Ihrem Code aus.
Abhängigkeiten aktualisieren
Nehmen Sie in der Build-Datei Ihres App-Moduls die folgenden Änderungen vor:
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")
Namespaces aktualisieren
Nehmen Sie in den Kotlin- und Java-basierten Codedateien Ihrer App die folgenden Änderungen vor. Alternativ können Sie dieses Script zum Umbenennen von Namespaces ausführen.
- Ersetzen Sie alle
androidx.wear.tiles.material.*
-Importe durchandroidx.wear.protolayout.material.*
. Führen Sie diesen Schritt auch für die Bibliothekandroidx.wear.tiles.material.layouts
aus. Ersetzen Sie die meisten anderen
androidx.wear.tiles.*
-Importe durchandroidx.wear.protolayout.*
.Importe für
androidx.wear.tiles.EventBuilders
,androidx.wear.tiles.RequestBuilders
,androidx.wear.tiles.TileBuilders
undandroidx.wear.tiles.TileService
sollten unverändert bleiben.Einige verworfene Methoden aus den Klassen „TileService“ und „TileBuilder“ wurden umbenannt:
TileBuilders
:getTimeline()
bisgetTileTimeline()
undsetTimeline()
bissetTileTimeline()
TileService
– alter Preis:onResourcesRequest()
, neuer Preis:onTileResourcesRequest()
RequestBuilders.TileRequest
:getDeviceParameters()
bisgetDeviceConfiguration()
,setDeviceParameters()
bissetDeviceConfiguration()
,getState()
bisgetCurrentState()
undsetState()
bissetCurrentState()