Nehmen Sie die folgenden Abhängigkeiten in die Datei build.gradle
Ihrer Anwendung auf, um mit der Bereitstellung von Kacheln aus Ihrer App zu beginnen.
Groovig
dependencies { // Use to implement support for wear tiles implementation "androidx.wear.tiles:tiles:1.4.0-beta01" // Use to utilize standard components and layouts in your tiles implementation "androidx.wear.protolayout:protolayout:1.2.0-beta01" // Use to utilize components and layouts with Material Design in your tiles implementation "androidx.wear.protolayout:protolayout-material:1.2.0-beta01" // Use to include dynamic expressions in your tiles implementation "androidx.wear.protolayout:protolayout-expression:1.2.0-beta01" // Use to preview wear tiles in your own app debugImplementation "androidx.wear.tiles:tiles-renderer:1.4.0-beta01" // Use to fetch tiles from a tile provider in your tests testImplementation "androidx.wear.tiles:tiles-testing:1.4.0-beta01" }
Kotlin
dependencies { // Use to implement support for wear tiles implementation("androidx.wear.tiles:tiles:1.4.0-beta01") // Use to utilize standard components and layouts in your tiles implementation("androidx.wear.protolayout:protolayout:1.2.0-beta01") // Use to utilize components and layouts with Material Design in your tiles implementation("androidx.wear.protolayout:protolayout-material:1.2.0-beta01") // Use to include dynamic expressions in your tiles implementation("androidx.wear.protolayout:protolayout-expression:1.2.0-beta01") // Use to preview wear tiles in your own app debugImplementation("androidx.wear.tiles:tiles-renderer:1.4.0-beta01") // Use to fetch tiles from a tile provider in your tests testImplementation("androidx.wear.tiles:tiles-testing:1.4.0-beta01") }
Kachel erstellen
Wenn Sie eine Kachel aus Ihrer Anwendung bereitstellen möchten, erstellen Sie eine Klasse, die TileService
erweitert, und implementieren Sie die Methoden wie im folgenden Codebeispiel gezeigt:
Kotlin
// Uses the ProtoLayout namespace for tile timeline objects. // If you haven't done so already, migrate to the ProtoLayout namespace. import androidx.wear.protolayout.TimelineBuilders.Timeline import androidx.wear.protolayout.material.Text import androidx.wear.tiles.TileBuilders.Tile private val RESOURCES_VERSION = "1" class MyTileService : TileService() { override fun onTileRequest(requestParams: RequestBuilders.TileRequest) = Futures.immediateFuture(Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( Text.Builder(this, "Hello world!") .setTypography(Typography.TYPOGRAPHY_DISPLAY1) .setColor(argb(0xFF000000.toInt())) .build())) .build()) override fun onTileResourcesRequest(requestParams: ResourcesRequest) = Futures.immediateFuture(Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ) }
Java
// Uses the ProtoLayout namespace for tile timeline objects. // If you haven't done so already, migrate to the ProtoLayout namespace. import androidx.wear.protolayout.TimelineBuilders.Timeline; import androidx.wear.protolayout.material.Text; import androidx.wear.tiles.TileBuilders.Tile; public class MyTileService extends TileService { private static final String RESOURCES_VERSION = "1"; @NonNull @Override protected ListenableFuture<Tile> onTileRequest( @NonNull TileRequest requestParams ) { return Futures.immediateFuture(new Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( new Text.Builder(this, "Hello world!") .setTypography(Typography.TYPOGRAPHY_DISPLAY1) .setColor(ColorBuilders.argb(0xFF000000)) .build())) .build() ); } @NonNull @Override protected ListenableFuture<Resources> onTileResourcesRequest( @NonNull ResourcesRequest requestParams ) { return Futures.immediateFuture(new Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ); } }
Fügen Sie als Nächstes im Tag <application>
der Datei AndroidManifest.xml
einen Dienst hinzu.
<service android:name=".MyTileService" android:label="@string/tile_label" android:description="@string/tile_description" android:icon="@drawable/tile_icon_round" android:roundIcon="@drawable/tile_icon_round" android:exported="true" android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER"> <intent-filter> <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" /> </intent-filter> <meta-data android:name="androidx.wear.tiles.PREVIEW" android:resource="@drawable/tile_preview" /> </service>
Der Berechtigungs- und Intent-Filter registriert diesen Dienst als Kachelanbieter.
Das Symbol, das Label und die Beschreibung werden dem Nutzer angezeigt, wenn er Kacheln auf seinem Smartphone oder seiner Smartwatch konfiguriert.
Verwende das Vorschau-Metadaten-Tag, um eine Vorschau der Kachel anzuzeigen, wenn du sie auf deinem Smartphone konfigurierst.
Übersicht über den Lebenszyklus des Tile-Dienstes
Nachdem du dein TileService
in deinem App-Manifest erstellt und deklariert hast, kannst du auf die Statusänderungen des Kacheldienstes reagieren.
TileService
ist ein gebundener Dienst. Ihre TileService
wird als Ergebnis Ihrer Anwendungsanfrage gebunden oder wenn das System mit ihr kommunizieren muss. Ein typischer Lebenszyklus eines gebundenen Dienstes umfasst die folgenden vier Callback-Methoden: onCreate()
, onBind()
, onUnbind()
und onDestroy()
. Das System ruft diese Methoden jedes Mal auf, wenn der Dienst in eine neue Lebenszyklusphase eintritt.
Zusätzlich zu den Callbacks, die den Lebenszyklus des gebundenen Dienstes steuern, können Sie andere Methoden implementieren, die für den Lebenszyklus TileService
spezifisch sind. Alle Kacheldienste müssen onTileRequest()
und onTileResourcesRequest()
implementieren, um auf Aktualisierungsanfragen vom System zu reagieren.
onTileAddEvent()
: Diese Methode wird nur aufgerufen, wenn der Nutzer deine Kachel zum ersten Mal hinzufügt und wenn er sie entfernt und noch einmal hinzufügt. Dies ist der beste Zeitpunkt für eine einmalige Initialisierung.onTileAddEvent()
wird nur aufgerufen, wenn der Satz von Kacheln neu konfiguriert wird, und nicht, wenn eine Kachel vom System erstellt wird. Wenn das Gerät beispielsweise neu gestartet oder eingeschaltet wird, wirdonTileAddEvent()
nicht für die bereits hinzugefügten Kacheln aufgerufen. Sie können stattdessengetActiveTilesAsync()
verwenden, um einen Snapshot der zu Ihnen gehörenden Kacheln abzurufen.onTileRemoveEvent()
: Das System ruft diese Methode nur auf, wenn der Nutzer deine Kachel entfernt.onTileEnterEvent()
: Das System ruft diese Methode auf, wenn eine von diesem Anbieter bereitgestellte Kachel auf dem Bildschirm erscheint.onTileLeaveEvent()
: Das System ruft diese Methode auf, wenn eine von diesem Anbieter bereitgestellte Kachel auf dem Bildschirm nicht mehr sichtbar ist.onTileRequest()
: Diese Methode wird aufgerufen, wenn eine neue Zeitachse von diesem Anbieter angefordert wird.onTileResourcesRequest()
: Das System ruft diese Methode auf, wenn das System ein Ressourcen-Bundle von diesem Anbieter anfordert. Dies kann passieren, wenn eine Tile zum ersten Mal geladen wird oder wenn sich die Ressourcenversion ändert.
Abfrage, welche Tiles aktiv sind
Aktive Kacheln sind Kacheln, die für die Anzeige auf der Smartwatch hinzugefügt wurden. Verwenden Sie die statische Methode getActiveTilesAsync()
von TileService
, um abzufragen, welche Kacheln aktiv sind, die zu Ihrer Anwendung gehören.
UI für Kacheln erstellen
Das Layout einer Kachel wird mithilfe eines Builder-Musters geschrieben. Das Layout einer Kachel ist wie eine Baumstruktur aufgebaut, die aus Layoutcontainern und grundlegenden Layoutelementen besteht. Jedes Layoutelement hat Eigenschaften, die Sie mit verschiedenen Setter-Methoden festlegen können.
Grundlegende Layoutelemente
Die folgenden visuellen Elemente aus der Bibliothek protolayout
werden zusammen mit den Material-Komponenten unterstützt:
Text
: Rendert einen Textstring mit optionalem Zeilenumbruch.Image
: rendert ein Bild.Spacer
: Bietet einen Innenabstand zwischen Elementen oder kann als Trennelement dienen, wenn Sie die Hintergrundfarbe festlegen.
Materialkomponenten
Zusätzlich zu den Grundelementen enthält die protolayout-material
-Bibliothek Komponenten, die für ein Kacheldesign gemäß den Material Design-Empfehlungen für die Benutzeroberfläche sorgen.
Button
: anklickbare kreisförmige Komponente, die ein Symbol enthalten soll.Chip
: anklickbare Komponente in Form eines Stadiums, die bis zu zwei Textzeilen und ein optionales Symbol enthalten kann.CompactChip
: anklickbare Komponente in Form eines Stadions, die eine Textzeile enthalten soll.TitleChip
: anklickbare Komponente in Form eines Stadions, ähnlich wieChip
, aber eine größere Höhe für den Titeltext.CircularProgressIndicator
: Kreisförmige Fortschrittsanzeige, die in einerEdgeContentLayout
platziert werden kann, um den Fortschritt am Bildschirmrand anzuzeigen.
Layoutcontainer
Die folgenden Container werden zusammen mit Material-Layouts unterstützt:
Row
: Ordnet untergeordnete Elemente horizontal nacheinander an.Column
: Ordnet untergeordnete Elemente vertikal nacheinander an.Box
: überlagert untergeordnete Elemente.Arc
: blendet untergeordnete Elemente in einem Kreis an.Spannable
: gilt speziell fürFontStyles
in Textabschnitten mit verschränkten Texten und Bildern. Weitere Informationen finden Sie unter Spannables.
Jeder Container kann ein oder mehrere untergeordnete Elemente enthalten, die wiederum Container sein können. Ein Column
kann beispielsweise mehrere Row
-Elemente als untergeordnete Elemente enthalten, was zu einem rasterähnlichen Layout führt.
Eine Kachel mit einem Containerlayout und zwei untergeordneten Layoutelementen könnte beispielsweise so aussehen:
Kotlin
private fun myLayout(): LayoutElement = Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VALIGN_BOTTOM) .addContent(Text.Builder() .setText("Hello world") .build() ) .addContent(Image.Builder() .setResourceId("image_id") .setWidth(dp(24f)) .setHeight(dp(24f)) .build() ).build()
Java
private LayoutElement myLayout() { return new Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VALIGN_BOTTOM) .addContent(new Text.Builder() .setText("Hello world") .build() ) .addContent(new Image.Builder() .setResourceId("image_id") .setWidth(dp(24f)) .setHeight(dp(24f)) .build() ).build(); }
Material layouts
Zusätzlich zu den Grundlayouts bietet die protolayout-material
-Bibliothek einige optimierte Layouts, die dafür vorgesehen sind, Elemente in bestimmten „Slots“ zu platzieren.
PrimaryLayout
: Dadurch wird eine einzelne primäre AktionCompactChip
unten platziert, der Inhalt darüber zentriert.MultiSlotLayout
: Positioniert primäre und sekundäre Labels mit optionalen Inhalten dazwischen und einem optionalenCompactChip
unten.MultiButtonLayout
: Hiermit werden Schaltflächen positioniert, die nach Materialrichtlinien angeordnet sind.EdgeContentLayout
: platziert Inhalte am Rand eines Bildschirms, z. B.CircularProgressIndicator
. Wenn Sie dieses Layout verwenden, werden die entsprechenden Ränder und Abstände automatisch auf den darin enthaltenen Inhalt angewendet.
Bögen
Die folgenden untergeordneten Arc
-Container werden unterstützt:
ArcLine
: Hiermit wird eine gebogene Linie um den Bogen herum gerendert.ArcText
: rendert den gebogenen Text im BogenArcAdapter
: rendert ein grundlegendes Layoutelement im Bogen, der tangens zum Bogen gezeichnet wird.
Weitere Informationen finden Sie in der Referenzdokumentation zu den einzelnen Elementtypen.
Modifikatoren
Auf jedes verfügbare Layoutelement können optional Modifikatoren angewendet werden. Verwenden Sie diese Modifikatoren für folgende Zwecke:
- Sie ändern das visuelle Erscheinungsbild des Layouts. Fügen Sie Ihrem Layoutelement z. B. einen Hintergrund, einen Rahmen oder einen Innenrand hinzu.
- Fügen Sie Metadaten zum Layout hinzu. Fügen Sie beispielsweise Ihrem Layoutelement einen Semantikmodifikator hinzu, der mit Screenreadern verwendet werden soll.
- Fügen Sie Funktionen hinzu. Fügen Sie Ihrem Layoutelement beispielsweise einen anklickbaren Modifikator hinzu, um Ihre Kachel interaktiv zu machen. Weitere Informationen findest du unter Mit Kacheln interagieren.
Beispielsweise können wir das Standarddesign und die Metadaten eines Image
anpassen, wie im folgenden Codebeispiel gezeigt:
Kotlin
private fun myImage(): LayoutElement = Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(Modifiers.Builder() .setBackground(Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(Padding.Builder().setStart(dp(12f)).build()) .setSemantics(Semantics.builder() .setContentDescription("Image description") .build() ).build() ).build()
Java
private LayoutElement myImage() { return new Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(new Modifiers.Builder() .setBackground(new Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(new Padding.Builder().setStart(dp(12f)).build()) .setSemantics(new Semantics.Builder() .setContentDescription("Image description") .build() ).build() ).build(); }
Spannables
Ein Spannable
ist eine spezielle Art von Container, der Elemente ähnlich wie Text anstellt. Dies ist nützlich, wenn Sie nur auf einen Teilstring in einem größeren Textblock einen anderen Stil anwenden möchten, was mit dem Element Text
nicht möglich ist.
Ein Spannable
-Container wird mit untergeordneten Span
gefüllt. Andere untergeordnete Elemente oder verschachtelte Spannable
-Instanzen sind nicht zulässig.
Es gibt zwei Arten von untergeordneten Span
-Elementen:
SpanText
: Text mit einem bestimmten Stil wird gerendert.SpanImage
: rendert ein Bild inline mit Text.
Sie können beispielsweise „world“ in einer „Hello world“-Kachel kursiv formatieren und ein Bild zwischen den Wörtern einfügen, wie im folgenden Codebeispiel gezeigt:
Kotlin
private fun mySpannable(): LayoutElement = Spannable.Builder() .addSpan(SpanText.Builder() .setText("Hello ") .build() ) .addSpan(SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(SpanText.Builder() .setText("world") .setFontStyle(FontStyle.Builder() .setItalic(true) .build()) .build() ).build()
Java
private LayoutElement mySpannable() { return new Spannable.Builder() .addSpan(new SpanText.Builder() .setText("Hello ") .build() ) .addSpan(new SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(new SpanText.Builder() .setText("world") .setFontStyle(newFontStyle.Builder() .setItalic(true) .build()) .build() ).build(); }
Mit Ressourcen arbeiten
Ansichten haben keinen Zugriff auf die Ressourcen deiner App. Das bedeutet, dass du eine Android-Bild-ID nicht an ein Image
-Layoutelement übergeben kannst und nicht erwarten kannst, dass das Problem aufgelöst wird. Überschreiben Sie stattdessen die Methode onTileResourcesRequest()
und geben Sie alle Ressourcen manuell an.
Es gibt zwei Möglichkeiten, Bilder innerhalb der Methode onTileResourcesRequest()
bereitzustellen:
- Stelle mit
setAndroidResourceByResId()
eine Drawable-Ressource bereit. - Stellen Sie mithilfe von
setInlineResource()
ein dynamisches Bild alsByteArray
bereit.
Kotlin
override fun onTileResourcesRequest( requestParams: ResourcesRequest ) = Futures.immediateFuture( Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", ImageResource.Builder() .setAndroidResourceByResId(AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", ImageResource.Builder() .setInlineResource(InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() )
Java
@Override protected ListenableFuture<Resources> onTileResourcesRequest( @NonNull ResourcesRequest requestParams ) { return Futures.immediateFuture( new Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", new ImageResource.Builder() .setAndroidResourceByResId(new AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", new ImageResource.Builder() .setInlineResource(new InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() ); }
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Zu ProtoLayout-Namespaces migrieren
ConstraintLayout
in „Schreiben“- Benutzerdefinierte Kacheln für Schnelleinstellungen für Apps erstellen