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") }
Tworzenie kafelka
Aby udostępnić kafelek z aplikacji, utwórz klasę rozszerzającą klasę TileService
i zaimplementuj metody, jak pokazano w tym przykładowym kodzie:
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>
w 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.
Omówienie cyklu życia usługi mapy
Po utworzeniu i zadeklarowaniu TileService
w pliku manifestu aplikacji możesz reagować na zmiany stanu usługi kafelka.
TileService
to powiązana usługa. Twoje TileService
jest powiązane z Twoim żądaniem aplikacji lub jeśli system musi się z nią komunikować. Typowy cykl życia usługi powiązanej obejmuje 4 metody wywołania zwrotnego: onCreate()
, onBind()
, onUnbind()
i onDestroy()
. System wywołuje te metody za każdym razem, gdy usługa wchodzi w nową fazę cyklu życia.
Oprócz wywołań zwrotnych, które kontrolują cykl życia powiązanej usługi, możesz też implementować inne metody związane z cyklem życia TileService
. Wszystkie usługi kafelków muszą implementować onTileRequest()
i onTileResourcesRequest()
, aby odpowiadać na żądania aktualizacji z systemu.
onTileAddEvent()
: system wywołuje tę metodę tylko wtedy, gdy użytkownik po raz pierwszy dodaje kafelek i gdy usuwa go, a następnie ponownie dodaje. To najlepszy moment na wykonanie jednorazowej inicjalizacji.onTileAddEvent()
jest wywoływany tylko wtedy, gdy zestaw kafelków jest przekonfigurowany, a nie za każdym razem, gdy system tworzy kafelek. Na przykład po ponownym uruchomieniu lub włączeniu urządzenia funkcjaonTileAddEvent()
nie jest wywoływana w przypadku kafelków, które zostały już dodane. Możesz użyć kodugetActiveTilesAsync()
, aby uzyskać podgląd, które Twoje kafelki są aktywne.onTileRemoveEvent()
: system wywołuje tę metodę tylko wtedy, gdy użytkownik usunie Twoją kartę.onTileEnterEvent()
: system wywołuje tę metodę, gdy kafelek udostępniony przez tego dostawcę pojawi się na ekranie.onTileLeaveEvent()
: system wywołuje tę metodę, gdy kafelek udostępniony przez tego dostawcę znika z ekranu.onTileRequest()
: system wywołuje tę metodę, gdy prosi o nową oś czasu od tego dostawcy.onTileResourcesRequest()
: system wywołuje tę metodę, gdy prosi o pakiet zasobów od tego dostawcy. Może się to zdarzyć przy pierwszym wczytaniu kafelka lub za każdym razem, gdy zmienia się wersja zasobu.
Zapytanie o to, które kafelki są aktywne
Aktywne karty to karty, które zostały dodane do wyświetlania na zegarku. Aby sprawdzić, które kafelki należące do Twojej aplikacji są aktywne, użyj statycznej metody TileService
getActiveTilesAsync()
.
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 Material Design:
Text
: renderuje ciąg tekstowy, opcjonalnie z zawijaniem.Image
: renderuje obraz.Spacer
: zapewnia wypełnienie między elementami lub może pełnić funkcję separatora po ustawieniu koloru tła.
Komponenty materiału
Oprócz podstawowych elementów biblioteka protolayout-material
zawiera komponenty, które zapewniają projekt kafelka zgodny z zaleceniami dotyczącymi interfejsu Material Design.
Button
: klikalny komponent kołowy przeznaczony do umieszczania 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 1 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ątrz elementuEdgeContentLayout
, aby wyświetlać postęp na krawędziach ekranu.
Kontenery układu
Obsługiwane są te kontenery i układy Material:
Row
: rozmieszcza elementy podrzędne poziomo, jeden pod drugim.Column
: rozmieszcza elementy podrzędne pionowo, jeden pod drugim.Box
: nakłada podrzędne elementy jeden na drugim.Arc
: rozmieszcza elementy podrzędne w kółku.Spannable
: stosuje się do konkretnych sekcji tekstuFontStyles
oraz do przeplatania tekstu z obrazami. Więcej informacji znajdziesz w artykule Spannables (w języku angielskim).
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(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(); }
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 na dole pojedyncze główne działanieCompactChip
, 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
: umieszcza zestaw przycisków rozmieszczonych zgodnie ze wskazówkami Material Design.EdgeContentLayout
: umieszcza treści na krawędzi ekranu, np.CircularProgressIndicator
. Gdy używasz tego układu, zawartość jest automatycznie wypełniana odpowiednimi marginesami i wypełnieniem.
Łuki
Obsługiwane są te elementy potomne kontenera Arc
:
ArcLine
: powoduje wyrenderowanie wygiętej linii wokół łuku.ArcText
: renderuje zakrzywiony tekst w elementie Arc.ArcAdapter
: renderuje podstawowy element układu na łuku, narysowanym wzdłuż łuku dotyczącego.
Więcej informacji znajdziesz w dokumentacji 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
Span
dziećmi. Inne elementy podrzędne ani zagnieżdżone elementy Spannable
nie są dozwolone.
Istnieją 2 rodzaje elementów podrzędnych Span
:
Możesz na przykład umieścić w nawiasach kursywą wyraz „world” w płytce „Hello world” i wstawić między słowami obraz, jak pokazano 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