Pierwsze kroki z kafelkami


Aby zacząć udostępniać karty z aplikacji, dodaj te zależności w pliku build.gradle aplikacji.

Odlotowe

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

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

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

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

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

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

Kotlin

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

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

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

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

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

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

Kluczowe pojęcia

Kafelki nie są tworzone w taki sam sposób jak aplikacje na Androida i wykorzystują inne koncepcje:

  • Szablony układu: określają ogólny układ elementów wizualnych na wyświetlaczu. Służy do tego funkcja primaryLayout().
  • Elementy układu: reprezentują pojedynczy element graficzny, taki jak przycisk lub karta, albo kilka takich elementów zgrupowanych za pomocą kolumny, buttonGroup lub podobnego elementu. Są one umieszczone 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 z wersji.
  • Oś czasu: obiekt TimelineBuilders.Timeline to lista co najmniej 1 instancji obiektu układu. Możesz podać różne mechanizmy i wyrażenia, aby wskazać, kiedy mechanizm renderujący powinien przełączyć się z jednego obiektu układu na inny, np. aby przestać wyświetlać układ o określonej godzinie.
  • Stan: struktura danych typu StateBuilders.State przekazywana między kafelkiem a aplikacją, która umożliwia komunikację między tymi 2 komponentami. Jeśli na przykład na kafelku zostanie kliknięty przycisk, stan będzie zawierać identyfikator przycisku. Możesz też wymieniać typy danych za pomocą mapy.
  • Kafel: obiekt TileBuilders.Tile reprezentujący kafel, który składa się z osi czasu, identyfikatora wersji zasobów, interwału aktualności i stanu.
  • Protolayout: to określenie pojawia się w nazwach różnych klas związanych z kartami i odnosi się do biblioteki Protolayout na Wear OS, czyli biblioteki graficznej używanej na różnych platformach Wear OS.

Tworzenie kafelka

Użyj Material3TileService (zalecane)

Podczas tworzenia kafelków Material 3 (androidx.wear.tiles:tiles:1.6.0 i nowszych) zawsze rozszerzaj klasę Material3TileService, a nie klasę niższego poziomu TileService. Material3TileService zapewnia opartą na języku Kotlin architekturę, która upraszcza tworzenie kafelków:

  • Wbudowane współprogramy Kotlin: zaimplementuj pojedynczą funkcję zawieszającą MaterialScope.tileResponse(requestParams: TileRequest): Tile zamiast używać ListenableFuture i zastępować onTileRequest().
  • Wstępnie skonfigurowany MaterialScope: tileResponse() działa z MaterialScope jako odbiorcą (skonfigurowanym za pomocą parametrów konstruktora, takich jak allowDynamicTheme i defaultColorScheme), więc nie musisz opakowywać układu w niepotrzebne wywołanie materialScope().
  • Rejestracja zasobów w ramach jednego wywołania: obejmuje ProtoLayoutScope, aby automatycznie rejestrować zasoby obrazów w tekście i zwracać zarówno układ kafelka, jak i zasoby w ramach jednego wywołania binder systemu. Material3TileService automatycznie obsługuje zasoby (final onTileResourcesRequest()), więc nie zastępuj onTileResourcesRequest().
class MyTileService : Material3TileService() {

    override suspend fun MaterialScope.tileResponse(requestParams: TileRequest): Tile =
        tile(
            timeline =
            Timeline.fromLayoutElement(
                primaryLayout(
                    mainSlot = {
                        text("Hello, World!".layoutString, typography = BODY_LARGE)
                    }
                )
            )
        )
}

Podstawowa architektura TileService

Klasa Material3TileService bazuje na klasie podstawowej TileService, która jest używana w pozostałych przykładach w tym przewodniku do ilustrowania pojęć niskiego poziomu.

Aby udostępnić kartę z aplikacji, zaimplementuj usługę typu TileService i zarejestruj ją w pliku manifestu. Na tej podstawie system żąda niezbędnych kafelków 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(
                        materialScope(this, requestParams.deviceConfiguration) {
                            primaryLayout(
                                mainSlot = {
                                    text("Hello, World!".layoutString, typography = BODY_LARGE)
                                }
                            )
                        }
                    )
                )
                .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.m3.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>

Uprawnienie i filtr intencji rejestrują tę usługę jako dostawcę kafelków.

Ikona, etykieta, opis i zasób podglądu są wyświetlane użytkownikowi podczas konfigurowania kart na telefonie lub zegarku. Pamiętaj, że zasób podglądu obsługuje wszystkie standardowe kwalifikatory zasobów Androida, więc można go dostosować do takich czynników jak rozmiar ekranu i język urządzenia. Dodatkowe zalecenia znajdziesz na liście kontrolnej wersji testowej.

Wdróż aplikację i dodaj kartę do karuzeli kart (jest też bardziej przyjazny dla deweloperów sposób wyświetlania podglądu karty, ale na razie zrób to ręcznie).

Kafelek Wear OS utworzony za pomocą Material 3, wyświetlający tekst „Hello World”.
Rysunek 1. „Hello World”.

Pełny przykład znajdziesz w przykładowym kodzie na GitHubie lub w ćwiczeniu z programowania.

Tworzenie interfejsu kafelków

Elementy interfejsu Material 3 Expressive są tworzone przy użyciu ustrukturyzowanego podejścia opartego na wzorcu bezpiecznego typowania w języku Kotlin.

Układ

Wskazówki dotyczące zasad projektowania, które pozwalają tworzyć skuteczne i elastyczne układy kafelków, znajdziesz w artykule Typowe układy kafelków.

Aby utworzyć układ:

  1. Inicjowanie zakresu Material Design: wywołaj funkcję materialScope(), podając wymagane parametry context i deviceConfiguration. Możesz uwzględnić parametry opcjonalne, takie jak allowDynamicTheme i defaultColorScheme. allowDynamicTheme jest domyślnie true, a defaultColorScheme reprezentuje ColorScheme używany, gdy kolory dynamiczne są niedostępne – na przykład gdy użytkownik wyłączył tę funkcję – lub gdy nie jest ona obsługiwana przez urządzenie, albo gdy allowDynamicTheme jest false). Jeśli używasz interfejsów API ImageResource, takich jak backgroundImage(), w niestandardowym TileService, wywołaj materialScopeWithResources().

  2. Tworzenie interfejsu w zakresie: wszystkie komponenty interfejsu danego układu kafelka muszą być zdefiniowane w wywołaniu lambda pojedynczego wywołania materialScope() najwyższego poziomu. Te funkcje komponentów, takie jak primaryLayout() i textEdgeButton(), są funkcjami rozszerzenia w MaterialScope i są dostępne tylko wtedy, gdy są wywoływane w tym zakresie odbiornika.

    materialScope(
        context = context,
        deviceConfiguration =
        requestParams.deviceConfiguration, // requestParams is passed to onTileRequest
        defaultColorScheme = myFallbackColorScheme
    ) {
        // inside the MaterialScope, you can call functions like primaryLayout()
        primaryLayout(
            titleSlot = { text(text = "Title".layoutString) },
            mainSlot = { text(text = "Main Content".layoutString) },
            bottomSlot = {
                textEdgeButton(
                    labelContent = { text("Action".layoutString) },
                    onClick = clickable()
                )
            }
        )
    }

Przedziały

W Material 3 układ kafelków wykorzystuje podejście inspirowane Compose, które korzysta z 3 różnych miejsc. Od góry do dołu są to:

  1. titleSlot, zwykle w przypadku tytułu głównego lub nagłówka.
  2. mainSlot, dla treści podstawowych.
  3. bottomSlot, często używany do działań lub informacji uzupełniających. W tym miejscu pojawia się też przycisk krawędzi.
Układ kafelków z polami titleSlot, mainSlot i bottomSlot
Rysunek 2. titleSlot, mainSlot i bottomSlot.

Zawartość każdego boksu jest następująca:

  • titleSlot (opcjonalnie): zwykle kilka słów wygenerowanych przez text().
  • mainSlot (obowiązkowy): komponenty uporządkowane w struktury takie jak wiersze, kolumny i grupy przycisków. Te komponenty można też rekurencyjnie umieszczać wewnątrz siebie, np. kolumna może zawierać wiersze.
  • bottomSlot (opcjonalnie): zwykle zawiera przycisk przylegający do krawędzi lub etykietę tekstową.

Kafelków nie można przewijać, więc nie ma komponentów do stronicowania, przewijania ani obsługi długich list treści. Zadbaj o to, aby treści były widoczne, gdy rozmiar czcionki się zwiększy lub tekst stanie się dłuższy po przetłumaczeniu.

Komponenty UI

Biblioteka protolayout-material3 zawiera wiele komponentów zaprojektowanych zgodnie ze specyfikacjami Material 3 Expressive i zaleceniami dotyczącymi interfejsu.

Przyciski

Przyciski są przede wszystkim zorientowane na działanie. Służą do wywoływania określonych działań. Zawartość każdego przycisku, np. ikona lub krótki tekst, określa działanie.

  • textButton(): przycisk z jednym miejscem na (krótki) tekst.
  • iconButton(): przycisk z jednym miejscem na ikonę.
  • avatarButton(): przycisk awatara w kształcie pigułki, który oferuje maksymalnie 3 miejsca na treści reprezentujące ułożone pionowo etykietę i etykietę dodatkową oraz obraz (awatar) obok nich.
  • imageButton(): klikalny przycisk graficzny, który nie oferuje dodatkowych boksów, tylko obraz (np. backgroundImage jako tło).
  • compactButton(): przycisk kompaktowy, który oferuje maksymalnie 2 miejsca na treści ułożone poziomo, reprezentujące ikonę i tekst obok niej.
  • button(): przycisk w kształcie pigułki, który oferuje maksymalnie 3 miejsca na treści reprezentujące etykietę i etykietę dodatkową ułożone pionowo oraz ikonę obok nich.

Przyciski krawędziowe

Przycisk krawędziowy to specjalny przycisk o pełnej szerokości, który jest zakotwiczony u dołu okrągłego ekranu zegarka i reprezentuje najważniejsze działanie, które można wykonać na bieżącym ekranie kafelka.

  • iconEdgeButton(): przycisk krawędziowy, który oferuje jedno miejsce na ikonę lub podobną okrągłą, małą treść.
  • textEdgeButton(): przycisk krawędziowy, który oferuje jedno miejsce na tekst lub podobnie długie i szerokie treści.

Karty

Karty są przede wszystkim zorientowane na informacje. Wyświetlają kolekcje powiązanych, uporządkowanych danych. Możesz tworzyć karty interaktywne, ale zwykle wyświetlają one podsumowanie informacji, które użytkownik może kliknąć, aby zobaczyć więcej szczegółów lub wykonać powiązane działanie.

  • titleCard(): karta tytułowa, która oferuje od 1 do 3 miejsc, zwykle na tekst.
  • appCard(): karta aplikacji, która oferuje do 5 miejsc, zwykle tekstowych.
  • textDataCard(): karta danych, która oferuje maksymalnie 3 pionowo ułożone boksy, zwykle tekstowe lub liczbowe.
  • iconDataCard(): karta danych, która oferuje maksymalnie 3 pionowo ułożone boksy, zwykle tekstowe lub liczbowe, z ikoną.
  • graphicDataCard(): karta danych graficznych, która zawiera miejsce na dane graficzne, takie jak wskaźnik postępu, oraz maksymalnie 2 miejsca ułożone pionowo, zwykle na opisy tekstowe.

Wskaźniki postępu

Grupowanie elementów układu

  • buttonGroup(): układ komponentu, który umieszcza elementy podrzędne w sekwencji poziomej.
  • primaryLayout(): układ pełnoekranowy, który reprezentuje sugerowany styl układu M3, który jest elastyczny i dba o rozmieszczenie elementów, wraz z zalecanymi marginesami i dopełnieniem.

Stosowanie motywu

W Material 3 Expressive system kolorów jest definiowany przez 29 standardowych ról kolorów, które są podzielone na 6 grup: podstawowe, drugorzędne, trzeciorzędne, błędy, powierzchnie i kontury.

System kolorów ekspresyjnych Material 3, który pokazuje role kolorów podzielone na grupy, takie jak podstawowe, drugorzędne, trzeciorzędne, błąd, powierzchnia i kontur.
Rysunek 3. System kolorów Material 3 Expressive.

ColorScheme mapuje każdą z tych 29 ról na odpowiedni kolor. Ponieważ jest to część MaterialScope, a komponenty muszą być tworzone w jej obrębie, automatycznie przyjmują one kolory ze schematu. Dzięki temu wszystkie elementy interfejsu automatycznie spełniają standardy Material Design.

Aby umożliwić użytkownikom wybór między zdefiniowanym przez Ciebie schematem kolorów (np. odzwierciedlającym kolory Twojej marki) a schematem dostarczonym przez system (pochodzącym z bieżącej tarczy zegarka użytkownika lub wybranym przez użytkownika), zainicjuj MaterialScope w ten sposób:

val myColorScheme =
    ColorScheme(
        primary = Color.rgb(0, 0, 255).argb, // Blue
        onPrimary = Color.rgb(255, 255, 255).argb, // White
        // 27 more
    )

materialScope(
    context = context,
    deviceConfiguration = requestParams.deviceConfiguration,
    defaultColorScheme = myColorScheme
) {
    // If the user selects "no theme" in settings, myColorScheme is used.
    // Otherwise, the system-provided theme is used.
}

Jeśli wybierzesz tę opcję, podaj monochromatyczną ikonę kafelka, aby można było ją prawidłowo zabarwić i zapewnić optymalną widoczność na dowolnym motywie.

Aby wymusić wyświetlanie kafelków w podanym schemacie kolorów, wyłącz obsługę dynamicznych motywów, ustawiając allowDynamicTheme na false:

materialScope(
    context = context,
    deviceConfiguration = requestParams.deviceConfiguration,
    allowDynamicTheme = false,
    defaultColorScheme = myColorScheme
) {
    // myColorScheme is *always* used.
}

Kolor

Każdy komponent używa podzbioru 29 ról kolorów zdefiniowanych przez ColorScheme. Na przykład przyciski używają maksymalnie 4 kolorów, które domyślnie są pobierane z grupy „podstawowej” aktywnego elementu ColorScheme:

Token komponentu ButtonColors Rola ColorScheme
containerColor podstawowe
iconColor onPrimary
labelColor onPrimary
secondaryLabelColor onPrimary (nieprzezroczystość 0,8)

Szczegółowe wskazówki dotyczące stosowania kolorów w projektach na Wear OS znajdziesz w przewodniku po projektowaniu kolorów.

W przypadku niektórych elementów interfejsu może być konieczne odstępstwo od domyślnych tokenów kolorów. Możesz na przykład chcieć, aby jeden element textEdgeButton używał kolorów z grupy „dodatkowe” lub „trzeciorzędne” zamiast „podstawowe”, aby się wyróżniał i zapewniał lepszy kontrast.

Kolory komponentów możesz dostosowywać na kilka sposobów:

  1. Używanie funkcji pomocniczej do wstępnie zdefiniowanych kolorów Używaj funkcji pomocniczych, takich jak filledTonalButtonColors(), aby stosować standardowe style przycisków w Material 3 Expressive. Te funkcje tworzą wstępnie skonfigurowane instancje ButtonColors, które mapują typowe style, takie jak wypełniony, tonalny lub konturowy, na odpowiednie role z aktywnego ColorScheme w MaterialScope. Dzięki temu możesz stosować spójne style bez ręcznego definiowania każdego koloru dla typowych typów przycisków.

    textEdgeButton(
        colors = filledButtonColors(), // default
        /* OR colors = filledTonalButtonColors() */
        /* OR colors = filledVariantButtonColors() */
        // ... other parameters
    )

    W przypadku kart użyj odpowiedniej rodziny funkcji filledCardColors().

    Możesz też zmodyfikować obiekt ButtonColors zwracany przez funkcje pomocnicze za pomocą metody copy(), jeśli chcesz zmienić tylko 1 lub 2 tokeny:

    textEdgeButton(
        colors =
        filledButtonColors()
            .copy(
                containerColor = colorScheme.tertiary,
                labelColor = colorScheme.onTertiary
            ),
        // ... other parameters
    )

  2. Wyraźnie określ zastępcze role kolorów. Utwórz własny obiekt ButtonColors i przekaż go do komponentu. W przypadku kart użyj odpowiedniego obiektu CardColors.

    textEdgeButton(
        colors =
        ButtonColors(
            // the materialScope makes colorScheme available
            containerColor = colorScheme.secondary,
            iconColor = colorScheme.secondaryDim,
            labelColor = colorScheme.onSecondary,
            secondaryLabelColor = colorScheme.onSecondary
        ),
        // ... other parameters
    )

  3. Określ stałe kolory (używaj z rozwagą). Zalecamy określanie kolorów według ich roli semantycznej (np. colorScheme.primary), ale możesz też podawać bezpośrednie wartości kolorów. Z tego podejścia należy korzystać oszczędnie, ponieważ może ono prowadzić do niespójności z ogólnym motywem, zwłaszcza jeśli motyw zmienia się dynamicznie.

    textEdgeButton(
        colors = filledButtonColors().copy(
            containerColor = android.graphics.Color.RED.argb, // Using named colors
            labelColor = 0xFFFFFF00.toInt().argb // Using a hex code for yellow
        ),
        // ... other parameters
    )

Typografia

Więcej informacji o skutecznym wykorzystywaniu typografii w projektach znajdziesz w przewodniku po projektowaniu typografii.

Aby zapewnić spójność wizualną na platformie Wear OS i zoptymalizować wydajność, cały tekst na kafelkach jest renderowany przy użyciu czcionki systemowej. Oznacza to, że kafelki nie obsługują niestandardowych krojów pisma. Na Wear OS 6 i nowszych jest to czcionka specyficzna dla OEM. W większości przypadków będzie to czcionka zmienna, która zapewnia bardziej ekspresyjny wygląd i bardziej szczegółową kontrolę.

Aby utworzyć styl tekstu, zwykle używa się metody text() w połączeniu ze stałymi typograficznymi. Ten komponent umożliwia korzystanie ze wstępnie zdefiniowanych ról typograficznych w Material 3 Expressive, co pomaga dostosować kafelek do sprawdzonych metod typograficznych, aby zapewnić czytelność i hierarchię. Biblioteka zawiera zestaw 18 semantycznych stałych typograficznych, takich jak BODY_MEDIUM. Te stałe wpływają też na osie czcionki inne niż rozmiar.

text(
    text = "Hello, World!".layoutString,
    typography = BODY_MEDIUM,
)

Aby mieć większą kontrolę, możesz wprowadzić dodatkowe ustawienia. W Wear OS 6 i nowszych wersjach prawdopodobnie będzie używana czcionka zmienna, którą można modyfikować w osiach kursywy, grubości, szerokości i zaokrąglenia. Możesz kontrolować te osie za pomocą parametru settings:

text(
    text = "Hello, World".layoutString,
    italic = true,

    // Use elements defined in androidx.wear.protolayout.LayoutElementBuilders.FontSetting
    settings =
    listOf(
        weight(500),
        width(100F),
        roundness(100)
    ),
)

Jeśli chcesz kontrolować rozmiar lub odstępy między literami (niezalecane), użyj basicText() zamiast text() i utwórz wartość właściwości fontStyle za pomocą fontStyle().

Kształt i marginesy

Promień narożnika prawie każdego komponentu możesz zmienić za pomocą właściwości shape. Wartości pochodzą z właściwości shapes w usłudze MaterialScope:

textButton(
    height = expand(),
    width = expand(),
    shape = shapes.medium, // OR another value like shapes.full
    colors = filledVariantButtonColors(),
    labelContent = { text("Hello, World!".layoutString) },
)

Jeśli po zmianie kształtu komponentu uznasz, że wokół krawędzi wyświetlacza jest za dużo lub za mało miejsca, dostosuj marginesy za pomocą parametru margin elementu primaryLayout():

primaryLayout(
    mainSlot = {
        textButton(
            shape = shapes.small,
            /* ... */
        )
    },
    // margin constants defined in androidx.wear.protolayout.material3.PrimaryLayoutMargins
    margins = MAX_PRIMARY_LAYOUT_MARGIN,
)

Łuki

Obsługiwane są te elementy podrzędne kontenera Arc:

  • ArcLine: renderuje zakrzywioną linię wokół łuku.
  • ArcText: renderuje zakrzywiony tekst w łuku.
  • ArcAdapter: renderuje podstawowy element układu w łuku, narysowany stycznie do ł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 następujących celach:

  • Zmień wygląd układu. Możesz na przykład dodać do elementu układu tło, obramowanie lub dopełnienie.
  • Dodaj metadane dotyczące układu. Możesz na przykład dodać modyfikator semantyki do elementu układu, aby używać go z czytnikami ekranu.
  • Dodaj funkcje. Możesz na przykład dodać do elementu układu modyfikator z możliwością kliknięcia, aby kafel stał się interaktywny. Więcej informacji znajdziesz w rozdziale Interakcja z kartami.

Możemy na przykład dostosować domyślny wygląd i metadane elementu Image, jak w tym przykładowym kodzie:

private fun myImage(): LayoutElement =
    Image.Builder()
        .setWidth(dp(24f))
        .setHeight(dp(24f))
        .setResourceId("image_id")
        .setModifiers(
            Modifiers.Builder()
                .setBackground(Background.Builder().setColor(argb(0xFFFF0000.toInt())).build())
                .setPadding(ModifiersBuilders.Padding.Builder().setStart(dp(12f)).build())
                .setSemantics(Semantics.Builder().setContentDescription("Image description").build())
                .build()
        )
        .build()

Spannables

Spannable to specjalny typ kontenera, który układa elementy podobnie jak tekst. Jest to przydatne, gdy chcesz zastosować inny styl tylko do jednego podłańcucha w większym bloku tekstu, co nie jest możliwe w przypadku elementu Text.

Kontener Spannable jest wypełniony elementami podrzędnymi Span. Inne elementy podrzędne lub zagnieżdżone instancje Spannable są niedozwolone.

Istnieją 2 typy dzieci Span:

  • SpanText: renderuje tekst w określonym stylu.
  • SpanImage: renderuje obraz w treści z tekstem.

Możesz na przykład pochylić słowo „world” w kafelku „Hello world” i wstawić obraz między słowami, jak w tym przykładowym kodzie:

private fun mySpannable(): LayoutElement =
    LayoutElementBuilders.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()

Praca z zasobami

Kafelki 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 oczekiwać, że zostanie on rozpoznany. Zamiast tego zastąp metodę onTileResourcesRequest() i podaj zasoby ręcznie.

Obrazy można podać w metodzie onTileResourcesRequest() na 2 sposoby:

override fun onTileResourcesRequest(
    requestParams: ResourcesRequest
) = Futures.immediateFuture(
    Resources.Builder()
        .setVersion("1")
        .addIdToImageMapping(
            "image_from_resource",
            ResourceBuilders.ImageResource.Builder()
                .setAndroidResourceByResId(
                    ResourceBuilders.AndroidImageResourceByResId.Builder()
                        .setResourceId(R.drawable.ic_walk)
                        .build()
                ).build()
        )
        .addIdToImageMapping(
            "image_inline",
            ResourceBuilders.ImageResource.Builder()
                .setInlineResource(
                    ResourceBuilders.InlineImageResource.Builder()
                        .setData(imageAsByteArray)
                        .setWidthPx(48)
                        .setHeightPx(48)
                        .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565)
                        .build()
                ).build()
        ).build()
)

Lista kontrolna obrazu podglądu kafelka

System wyświetla obraz podglądu kafelka, do którego odwołuje się manifest aplikacji na Androida, w edytorze karuzeli kafelków, aby dodać nowy kafelek. Ten edytor jest dostępny zarówno na urządzeniach z Wear OS, jak i w aplikacji towarzyszącej na telefonach.

Aby pomóc użytkownikom w pełni wykorzystać możliwości tego obrazu podglądu, sprawdź te szczegóły dotyczące kafelka:

  • Odzwierciedla najnowszy projekt. Podgląd powinien dokładnie odzwierciedlać najnowszy projekt kafelka.
  • Używa zalecanych wymiarów. Aby zapewnić jak najlepszą jakość wyświetlania i dobre wrażenia użytkowników, obraz podglądu powinien mieć wymiary 400 x 400 pikseli.
  • Używa statycznego motywu kolorystycznego. Użyj statycznego motywu kolorystycznego kafelka, a nie dynamicznego.
  • Zawiera ikonę aplikacji. Sprawdź, czy ikona aplikacji jest widoczna u góry obrazu podglądu.
  • Pokazuje stan wczytania/zalogowania. Podgląd powinien wyświetlać w pełni funkcjonalny stan „załadowany” lub „zalogowany”, bez pustych treści lub obiektów zastępczych.
  • Wykorzystaj reguły rozwiązywania konfliktów dotyczących zasobów na potrzeby dostosowywania (opcjonalnie). Rozważ użycie reguł rozpoznawania zasobów Androida, aby udostępniać podglądy zgodne z rozmiarem wyświetlacza urządzenia, językiem lub ustawieniami regionalnymi. Jest to szczególnie przydatne, jeśli wygląd kafelka różni się w zależności od urządzenia.