Aby zacząć udostępniać kafelki z aplikacji, dodaj te zależności do pliku build.gradle
aplikacji.
Groovy
dependencies { // Use to implement support for wear tiles implementation "androidx.wear.tiles:tiles:1.5.0-alpha04" // Use to utilize standard components and layouts in your tiles implementation "androidx.wear.protolayout:protolayout:1.3.0-alpha04" // Use to utilize components and layouts with Material Design in your tiles implementation "androidx.wear.protolayout:protolayout-material:1.3.0-alpha04" // Use to include dynamic expressions in your tiles implementation "androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04" // Use to preview wear tiles in your own app debugImplementation "androidx.wear.tiles:tiles-renderer:1.5.0-alpha04" // Use to fetch tiles from a tile provider in your tests testImplementation "androidx.wear.tiles:tiles-testing:1.5.0-alpha04" }
Kotlin
dependencies { // Use to implement support for wear tiles implementation("androidx.wear.tiles:tiles:1.5.0-alpha04") // Use to utilize standard components and layouts in your tiles implementation("androidx.wear.protolayout:protolayout:1.3.0-alpha04") // Use to utilize components and layouts with Material Design in your tiles implementation("androidx.wear.protolayout:protolayout-material:1.3.0-alpha04") // Use to include dynamic expressions in your tiles implementation("androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04") // Use to preview wear tiles in your own app debugImplementation("androidx.wear.tiles:tiles-renderer:1.5.0-alpha04") // Use to fetch tiles from a tile provider in your tests testImplementation("androidx.wear.tiles:tiles-testing:1.5.0-alpha04") }
Kluczowych pojęć
Kafelki nie są tworzone w taki sam sposób jak aplikacje na Androida i korzystają z innych koncepcji:
- Szablony układu: określają ogólne rozmieszczenie elementów wizualnych na ekranie. Płytka używa szablonu układu
EdgeContentLayout
, który zawiera wskaźnik postępu na krawędzi wyświetlacza, lubPrimaryLayout
, który nie wyświetla tego wskaźnika. - Elementy układu: reprezentują pojedynczy element graficzny, np.
Button
lubChip
, albo kilka takich elementów zgrupowanych za pomocą elementuColumn
,MultiButtonLayout
,MultiSlotLayout
lub podobnego. Są one umieszczane w szablonie układu. - Zasoby: obiekty
ResourceBuilders.Resources
składają się z mapy par klucz-wartość zasobów Androida (obrazów) wymaganych do renderowania układu oraz wersji. - Harmonogram: obiekt
TimelineBuilders.Timeline
to lista co najmniej 1 wystąpienia obiektu układu. Możesz stosować różne mechanizmy i wyrażenia, aby wskazać, kiedy renderowanie powinno przejść z jednego obiektu układu na inny, np. aby w określonym momencie przestać wyświetlać dany układ. - Stan: struktura danych typu
StateBuilders.State
przekazywana między kafelkiem a aplikacją, aby umożliwić komunikację tych dwóch komponentów. Jeśli np. użytkownik kliknie przycisk na kafelku, stan będzie zawierać identyfikator tego przycisku. Typy danych możesz też wymieniać za pomocą mapy. - Płytka: obiekt
TileBuilders.Tile
reprezentujący płytkę, który składa się z osi czasu, identyfikatora wersji zasobów, interwału świeżości i stanu. - Protolayout: ten termin pojawia się w nazwach różnych klas związanych z płytkami i odnosi się do biblioteki Protolayout na Wear OS, czyli biblioteki graficznej używanej na różnych platformach Wear OS.
Tworzenie kafelka
Aby udostępnić kafelek z aplikacji, zaimplementuj usługę typu TileService
i zarejestruj ją w pliku manifestu. W tym celu system wysyła żądania dotyczące niezbędnych płytek podczas wywołań onTileRequest()
i zasobów podczas wywołań onTileResourcesRequest()
.
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_BODY1) .setColor(argb(0xFFFFFFFF.toInt())) .build() ) ) .build() ) override fun onTileResourcesRequest(requestParams: ResourcesRequest) = Futures.immediateFuture( Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ) }
Następnie dodaj usługę w tagu <application>
pliku AndroidManifest.xml
.
<service android:name=".snippets.tile.MyTileService" android:label="@string/tile_label" android:description="@string/tile_description" android:icon="@mipmap/ic_launcher" 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>
Filtr uprawnień i zamiarów rejestruje tę usługę jako dostawcę kafelka.
Ikona, etykieta, opis i zasob do podglądu są wyświetlane użytkownikowi, gdy konfiguruje on karty na telefonie lub zegarku.
Wprowadź aplikację i dodaj kartę do karuzeli kart (jest też bardziej przyjazny dla dewelopera sposób wyświetlania podglądu karty, ale na razie wykonaj to ręcznie).
Rysunek 1. Płytka „Hello World”.
Pełny przykład znajdziesz w przykładowym kodzie na GitHubie lub w laboratorium kodu.
Tworzenie interfejsu dla płytek
Układ kafelka jest zapisywany za pomocą wzoru kreatora. Układ kafelka jest zbudowany jak drzewo, które składa się z kontenerów układu i podstawowych elementów układu. Każdy element układu ma właściwości, które możesz ustawiać za pomocą różnych metod settera.
Podstawowe elementy układu
Obsługiwane są te elementy wizualne z biblioteki protolayout
: Komponenty materiałowe:
Text
: renderuje ciąg tekstowy, opcjonalnie z zawijaniem.Image
: renderowanie obrazu.Spacer
: zapewnia odstęp między elementami lub może pełnić funkcję separatora po ustawieniu koloru tła.
Komponenty materiału
Oprócz elementów podstawowych biblioteka protolayout-material
zawiera komponenty, które zapewniają projekt kafelka zgodny z zaleceniami interfejsu Material Design.
Button
: klikalny okrągły element zawierający ikonę.Chip
: klikalny komponent w kształcie stadionu, który może zawierać maksymalnie 2 wiersze tekstu i opcjonalną ikonę.CompactChip
: klikalny komponent w kształcie stadionu, który mieści jeden wiersz tekstu.TitleChip
: klikalny element w kształcie stadionu podobny doChip
, ale o większej wysokości, aby pomieścić tekst tytułu.CircularProgressIndicator
: kołowy wskaźnik postępu, który można umieścić wewnątrzEdgeContentLayout
, aby wyświetlać postęp na krawędziach ekranu.
Kontenery układu
Obsługiwane są te kontenery wraz z układami Material Design:
Row
: elementy podrzędne są rozmieszczone poziomo, jeden pod drugim.Column
: elementy podrzędne są rozmieszczane pionowo, jeden pod drugim.Box
: elementy podrzędne są nakładane na siebie.Arc
: elementy podrzędne są rozmieszczone w kółku.Spannable
: pozwala zastosować określoneFontStyles
do sekcji tekstu, a także mieszać tekst z obrazami. Więcej informacji znajdziesz w artykule Spannables.
Każdy kontener może zawierać co najmniej 1 kontener podrzędny, który może być też kontenerem. Na przykład element Column
może zawierać wiele elementów Row
jako podrzędnych, co tworzy układ podobny do siatki.
Przykładem kafelka z układem kontenera i 2 elementami podrzędnymi może być:
Kotlin
private fun myLayout(): LayoutElement = Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VERTICAL_ALIGN_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(); }
Układy materiału
Oprócz podstawowych układów biblioteka protolayout-material
zawiera kilka układów z określonym układem, które służą do umieszczania elementów w określonych „miejscach”.
PrimaryLayout
: umieszcza pojedyncze główne działanieCompactChip
na dole, a nad nim treści wyśrodkowane.MultiSlotLayout
: umieszcza etykiety główne i dodatkowe z opcjonalnymi treściami pomiędzy nimi oraz opcjonalną etykietąCompactChip
na dole.MultiButtonLayout
: ustawia zestaw przycisków rozmieszczonych zgodnie ze wskazówkami Material Design.EdgeContentLayout
: umieszcza treści na krawędzi ekranu, na przykładCircularProgressIndicator
. Gdy używasz tego układu, zawartość jest automatycznie wyświetlana z odpowiednimi marginesami i wypełnieniem.
Łuki
Obsługiwane są te elementy potomne kontenera Arc
:
ArcLine
: powoduje wyświetlenie wygiętej linii wokół łuku.ArcText
: renderowanie zakrzywionego tekstu w elementach łukowych.ArcAdapter
: element podstawowego układu jest renderowany na łuku, narysowany wzdłuż łuku.
Więcej informacji znajdziesz w dokumentacji referencyjnej dotyczącej poszczególnych typów elementów.
Modyfikatory
Do każdego dostępnego elementu układu można opcjonalnie zastosować modyfikatory. Używaj tych modyfikatorów w tych celach:
- Zmienianie wizualnego wyglądu układu. Możesz np. dodać tło, obramowanie lub wypełnienie do elementu układu.
- Dodaj metadane dotyczące układu. Możesz na przykład dodać do elementu układu modyfikator semantyczny na potrzeby czytników ekranu.
- Dodawanie funkcji. Możesz na przykład dodać do elementu układu modyfikator z możliwością kliknięcia, aby kafelek stał się interaktywny. Więcej informacji znajdziesz w artykule Interakcja z kartami.
Możemy na przykład dostosować domyślny wygląd i metadane Image
,
jak pokazano w tym przykładowym kodzie:
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(); }
Rozszerzenia
Spannable
to specjalny typ kontenera, który rozmieszcza elementy w sposób podobny do tekstu. Jest to przydatne, gdy chcesz zastosować inny styl tylko do jednego podciągu w większym bloku tekstu. Nie jest to możliwe w przypadku elementu Text
.
Kontenerek Spannable
jest wypełniony elementami podrzędnymi Span
. Inne podrzędne lub zagnieżdżone instancje Spannable
są niedozwolone.
Istnieją 2 rodzaje elementów podrzędnych Span
:
Możesz na przykład umieścić kursywę w słowie „world” na kafelku „Hello world” i wstawić między słowami obraz, jak w tym przykładzie kodu:
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(); }
Praca z zasobami
Płytki nie mają dostępu do żadnych zasobów aplikacji. Oznacza to, że nie możesz przekazać identyfikatora obrazu Androida do elementu układu Image
i spodziewać się, że zostanie on rozwiązany. Zamiast tego zastąpij metodę onTileResourcesRequest()
i ręcznie podaj zasoby.
Obrazy można przesłać w ramach metody onTileResourcesRequest()
na 2 sposoby:
- Podaj zasób do rysowania za pomocą
setAndroidResourceByResId()
. - Prześlij obraz dynamiczny jako
ByteArray
, używającsetInlineResource()
.
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() ); }
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy obsługa JavaScript jest wyłączona
- Migracja do przestrzeni nazw ProtoLayout
ConstraintLayout
w Nowym poście- Tworzenie niestandardowych kafelków Szybkich ustawień dla aplikacji