Erste Schritte mit Kacheln

Um mit der Bereitstellung von Kacheln aus Ihrer App zu beginnen, schließen Sie die folgenden Abhängigkeiten in die Datei build.gradle Ihrer App.

Cool

dependencies {
    // Use to implement support for wear tiles
    implementation "androidx.wear.tiles:tiles:1.4.0"

    // Use to utilize standard components and layouts in your tiles
    implementation "androidx.wear.protolayout:protolayout:1.2.0"

    // Use to utilize components and layouts with Material Design in your tiles
    implementation "androidx.wear.protolayout:protolayout-material:1.2.0"

    // Use to include dynamic expressions in your tiles
    implementation "androidx.wear.protolayout:protolayout-expression:1.2.0"

    // Use to preview wear tiles in your own app
    debugImplementation "androidx.wear.tiles:tiles-renderer:1.4.0"

    // Use to fetch tiles from a tile provider in your tests
    testImplementation "androidx.wear.tiles:tiles-testing:1.4.0"
}

Kotlin

dependencies {
    // Use to implement support for wear tiles
    implementation("androidx.wear.tiles:tiles:1.4.0")

    // Use to utilize standard components and layouts in your tiles
    implementation("androidx.wear.protolayout:protolayout:1.2.0")

    // Use to utilize components and layouts with Material Design in your tiles
    implementation("androidx.wear.protolayout:protolayout-material:1.2.0")

    // Use to include dynamic expressions in your tiles
    implementation("androidx.wear.protolayout:protolayout-expression:1.2.0")

    // Use to preview wear tiles in your own app
    debugImplementation("androidx.wear.tiles:tiles-renderer:1.4.0")

    // Use to fetch tiles from a tile provider in your tests
    testImplementation("androidx.wear.tiles:tiles-testing:1.4.0")
}

Kachel erstellen

Um eine Kachel aus Ihrer Anwendung bereitzustellen, erstellen Sie eine Klasse, die das TileService 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 einen Dienst im <application>-Tag Ihres AndroidManifest.xml-Datei.

<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 konfiguriert auf dem Smartphone oder der Smartwatch.

Mit dem Metadaten-Tag für die Vorschau können Sie bei der Konfiguration eine Vorschau der Kachel anzeigen lassen auf deinem Smartphone.

Übersicht über den Lebenszyklus des Tile-Dienstes

Nachdem du TileService in deinem App-Manifest erstellt und deklariert hast, auf Statusänderungen des Kacheldienstes reagieren kann.

TileService ist ein gebundener Dienst. Als Ergebnis ist Ihre TileService gebunden oder ob das System mit ihr kommunizieren muss. Ein typisches bound-service life enthält die folgenden vier Callback-Methoden: onCreate(), onBind(), onUnbind() und onDestroy(). Das System ruft diese Methoden jedes Mal auf, wenn der Dienst eine neue Lebenszyklusphase beginnt.

Zusätzlich zu den Callbacks, die den Lebenszyklus des gebundenen Dienstes steuern, können Sie Implementieren Sie weitere Methoden, die für den TileService-Lebenszyklus spezifisch sind. Alle Kacheln Dienste müssen onTileRequest() und onTileResourcesRequest() implementieren, um auf Systemanforderungen zu reagieren.

  • onTileAddEvent(): Das System ruft diese Methode nur auf, wenn der Nutzer fügt Ihre Kachel zum ersten Mal hinzu. Wenn der Nutzer Ihre Kachel entfernt und hinzufügt, erneut öffnen. Dies ist der beste Zeitpunkt für eine einmalige Initialisierung.

    onTileAddEvent() wird nur aufgerufen, wenn der Satz von Kacheln neu konfiguriert ist. nicht, wenn eine Kachel vom System erstellt wird. Beispiel: Wenn das Gerät neu gestartet oder eingeschaltet ist, wird onTileAddEvent() für die Kacheln nicht aufgerufen die bereits hinzugefügt wurden. Sie können getActiveTilesAsync() verwenden um zu sehen, welche Kacheln zu Ihnen gehören aktiv sind.

  • onTileRemoveEvent(): Das System ruft diese Methode nur auf, wenn der Nutzer entfernt Ihre Kachel.

  • onTileEnterEvent(): Das System ruft diese Methode auf, wenn eine Kachel die von diesem Anbieter bereitgestellt wurden, auf dem Bildschirm zu sehen sind.

  • onTileLeaveEvent(): Das System ruft diese Methode auf, wenn eine Kachel die von diesem Anbieter bereitgestellt wurden, nicht auf dem Bildschirm zu sehen sind.

  • onTileRequest(): Das System ruft diese Methode auf, wenn das System fordert von diesem Anbieter eine neue Zeitachse an.

  • onTileResourcesRequest(): Das System ruft diese Methode auf, wenn der fordert das System ein Ressourcenpaket von diesem Anbieter an. Das kann passieren, wenn eine Kachel zum ersten Mal geladen wird oder wenn die Ressourcenversion Änderungen.

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 zum Abfragen der Kacheln die zu deiner App gehören, aktiv sind.

UI für Kacheln erstellen

Das Layout einer Kachel wird mithilfe eines Builder-Musters geschrieben. Das Layout einer Kachel ist die wie ein Baum aufgebaut sind und aus Layoutcontainern und einem einfachen Layout Elemente. Jedes Layoutelement verfügt über Eigenschaften, die Sie über verschiedene Setter-Methoden.

Grundlegende Layoutelemente

Die folgenden visuellen Elemente aus der protolayout-Bibliothek werden unterstützt: zusammen mit den Material Components:

  • Text: wird gerendert einen Textstring mit optionalem Zeilenumbruch.
  • Image: ein Bild rendert.
  • Spacer: bietet Abstände zwischen Elementen oder kann als Trennelement dienen, wenn Sie seine die Hintergrundfarbe.

Materialkomponenten

Zusätzlich zu den Grundelementen bietet die protolayout-material-Bibliothek Komponenten, die ein Kacheldesign im Einklang mit der Benutzeroberfläche von Material Design sicherstellen Empfehlungen.

  • Button: anklickbar kreisförmige Komponente, die ein Symbol enthalten soll.
  • Chip: anklickbar stadionförmige Komponente, die bis zu zwei Textzeilen und ein optionales Symbol.

  • CompactChip: anklickbare, stadionförmige Komponente, die eine Textzeile enthalten soll.

  • TitleChip: anklickbare, stadionförmige Komponente ähnlich wie Chip, aber mit einem größeren Höhe für den Titeltext.

  • CircularProgressIndicator: eine kreisförmige Fortschrittsanzeige, EdgeContentLayout, um den Fortschritt am Rand des Bildschirm.

Layoutcontainer

Die folgenden Container werden zusammen mit dem Element Material unterstützt. Layouts:

  • Row: Legenden untergeordnete Elemente horizontal nacheinander angeordnet.
  • Column: legt untergeordnete Elemente vertikal nacheinander an.
  • Box: Overlays untergeordnete Elemente übereinander liegen.
  • Arc: Legenden untergeordnete Elemente in einem Kreis.
  • Spannable: wendet spezifische FontStyles in Textabschnitte und verschränkte Texte und Bilder. Weitere Informationen Weitere Informationen finden Sie unter Spannables.

Jeder Container kann ein oder mehrere untergeordnete Elemente enthalten, die wiederum Container. Ein Column kann beispielsweise mehrere Row-Elemente wie folgt enthalten: untergeordneten Elementen, was zu einem rasterähnlichen Layout führt.

Beispiel: Eine Kachel mit einem Container-Layout und zwei untergeordneten Layout-Elementen könnte wie folgt 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

Neben den grundlegenden Layouts bietet die protolayout-material-Bibliothek einige Spezielle Layouts, die darauf ausgelegt sind, Elemente in bestimmten „Slots“ zu halten.

  • PrimaryLayout: platziert eine primäre Aktion CompactChip unten mit dem Inhalte in der Mitte darüber.

  • MultiSlotLayout: Positionierung von primären und sekundären Labels mit optionalen Inhalten zwischen und eine optionale CompactChip am unteren Rand.

  • MultiButtonLayout: platziert eine Reihe von Schaltflächen, die nach Material Design .

  • EdgeContentLayout: Position von Inhalten am Rand eines Bildschirms, z. B. CircularProgressIndicator. Bei Verwendung dieses Layouts werden die darin enthaltenen Inhalte werden automatisch die passenden Ränder und die entsprechenden Abstände angewendet.

Bögen

Die folgenden untergeordneten Arc-Container werden unterstützt:

  • ArcLine: rendert eine gebogene Linie um den Bogen
  • ArcText: rendert den gekrümmten Text im Bogen
  • ArcAdapter: Rendert ein grundlegendes Layoutelement im Bogen, das tangens zum Bogen gezeichnet wird.

Weitere Informationen finden Sie in der Referenzdokumentation für jeden der Elementtypen.

Modifikatoren

Auf jedes verfügbare Layoutelement können optional Modifikatoren angewendet werden. Verwenden Sie diese Modifikatoren für folgende Zwecke nutzen:

  • Das visuelle Erscheinungsbild des Layouts ändern. Fügen Sie beispielsweise einen Hintergrund, Rahmen oder Abstand zum Layoutelement.
  • Fügen Sie Metadaten zum Layout hinzu. Fügen Sie beispielsweise einen Semantikmodifikator zu Ihrem Layoutelement zur Verwendung mit Screenreadern.
  • Fügen Sie Funktionen hinzu. Fügen Sie Ihrem Layout beispielsweise einen anklickbaren Modifikator hinzu. -Element, um Ihre Kachel interaktiv zu machen. Weitere Informationen finden Sie unter Mit Kacheln interagieren

Beispielsweise können wir das Standarddesign und die Metadaten eines Image, wie gezeigt im folgenden Codebeispiel:

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 Text. Dies ist nützlich, wenn Sie einen anderen Stil Teilzeichenfolge in einen größeren Textblock einfügen, was mit der Text-Element.

Ein Spannable-Container ist gefüllt mit Span Kinder. Andere untergeordnete Elemente oder verschachtelte Spannable-Instanzen sind nicht zulässig.

Es gibt zwei Arten von untergeordneten Span-Elementen:

  • SpanText: Rendert Text mit einem bestimmten Stil.
  • SpanImage: rendert ein Bild inline mit Text.

Sie können z. B. „Welt“ kursiv formatieren. in einem „Hello World“-Element Kachel und eine zwischen den Wörtern ein, wie im folgenden Codebeispiel veranschaulicht:

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 Sie kann keine Android-Bild-ID an ein Image-Layoutelement übergeben und erwartet, gelöst werden muss. Überschreiben Sie stattdessen onTileResourcesRequest() und stellen alle Ressourcen manuell bereit.

Es gibt zwei Möglichkeiten, Bilder im onTileResourcesRequest() bereitzustellen. :

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()
);
}