Чтобы начать предоставлять тайлы из вашего приложения, добавьте следующие зависимости в файл build.gradle вашего приложения.
Groovy
dependencies { // Use to implement support for wear tiles implementation "androidx.wear.tiles:tiles:1.5.0" // Use to utilize standard components and layouts in your tiles implementation "androidx.wear.protolayout:protolayout:1.3.0" // Use to utilize components and layouts with Material Design in your tiles implementation "androidx.wear.protolayout:protolayout-material:1.3.0" // Use to include dynamic expressions in your tiles implementation "androidx.wear.protolayout:protolayout-expression:1.3.0" // Use to preview wear tiles in your own app debugImplementation "androidx.wear.tiles:tiles-renderer:1.5.0" // Use to fetch tiles from a tile provider in your tests testImplementation "androidx.wear.tiles:tiles-testing:1.5.0" }
Kotlin
dependencies { // Use to implement support for wear tiles implementation("androidx.wear.tiles:tiles:1.5.0") // Use to utilize standard components and layouts in your tiles implementation("androidx.wear.protolayout:protolayout:1.3.0") // Use to utilize components and layouts with Material Design in your tiles implementation("androidx.wear.protolayout:protolayout-material:1.3.0") // Use to include dynamic expressions in your tiles implementation("androidx.wear.protolayout:protolayout-expression:1.3.0") // Use to preview wear tiles in your own app debugImplementation("androidx.wear.tiles:tiles-renderer:1.5.0") // Use to fetch tiles from a tile provider in your tests testImplementation("androidx.wear.tiles:tiles-testing:1.5.0") }
Ключевые понятия
Плитки создаются не так, как приложения для Android, и используют другие концепции:
- Шаблоны компоновки: определяют общее расположение визуальных элементов на экране. Это достигается с помощью функции
primaryLayout(). - Элементы макета: представляют собой отдельный графический элемент, например, кнопку или карточку , или несколько таких элементов, сгруппированных вместе с помощью столбца , группы кнопок или аналогичного элемента. Они встраиваются в шаблон макета .
- Ресурсы: Объекты
ResourceBuilders.Resourcesпредставляют собой карту пар ключ-значение ресурсов Android (изображений), необходимых для отображения макета, и их версию . - Временная шкала: Объект
TimelineBuilders.Timelineпредставляет собой список из одного или нескольких экземпляров объекта макета . Вы можете указать различные механизмы и выражения, чтобы обозначить, когда рендерер должен переключиться с одного объекта макета на другой, например, чтобы прекратить отображение макета в определенный момент времени. - Состояние: Структура данных типа
StateBuilders.State, которая передается между плиткой и приложением, позволяя двум компонентам взаимодействовать друг с другом. Например, если на плитке нажата кнопка, состояние содержит идентификатор кнопки. Также можно обмениваться типами данных с помощью карты (map). - Tile: Объект
TileBuilders.Tile, представляющий собой тайл, состоящий из временной шкалы , идентификатора версии ресурсов , интервала актуальности и состояния . - Protolayout: Этот термин встречается в названиях различных классов, связанных с тайлами, и относится к библиотеке Protolayout для Wear OS , графической библиотеке, используемой на различных поверхностях Wear OS.
Создать плитку
Чтобы предоставить тайл из вашего приложения, реализуйте сервис типа TileService и зарегистрируйте его в манифесте. Система будет запрашивать необходимые тайлы при вызовах метода onTileRequest() и ресурсы при вызовах метода 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()) }
Далее добавьте службу внутри тега <application> в файле 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>
Фильтр разрешений и намерений регистрирует этот сервис как поставщика тайлов.
Значок, метка, описание и предварительный просмотр отображаются пользователю при настройке плиток на телефоне или часах. Обратите внимание, что предварительный просмотр поддерживает все стандартные квалификаторы ресурсов Android, поэтому его можно изменять в зависимости от таких факторов, как размер экрана и язык устройства. Дополнительные рекомендации см. в контрольном списке предварительного просмотра .
Разверните приложение и добавьте плитку в карусель плиток (есть и более удобный для разработчиков способ предварительного просмотра плитки , но пока делайте это вручную).

Полный пример можно найти в образце кода на GitHub или в Codelab .
Создание пользовательского интерфейса для плиток
Выразительные элементы пользовательского интерфейса Material 3 создаются с использованием структурированного подхода, основанного на типобезопасном шаблоне построения объектов Kotlin.
Макет
Рекомендации по принципам проектирования эффективных и адаптивных макетов для плиток см. в разделе «Распространенные макеты для плиток» .
Для создания макета выполните следующие действия:
Инициализация области видимости Material Design: вызовите функцию
materialScope(), указав необходимыйcontextиdeviceConfiguration. Вы можете включить необязательные параметры, такие какallowDynamicThemeиdefaultColorScheme. ПараметрallowDynamicThemeпо умолчанию имеетtrue, аdefaultColorSchemeпредставляет собойColorSchemeиспользуемую, когда динамические цвета недоступны (например, когда пользователь отключил эту функцию) или когда она не поддерживается устройством (или когдаallowDynamicThemeимеет значениеfalse).Создавайте пользовательский интерфейс в рамках заданной области видимости: все компоненты пользовательского интерфейса для заданного макета Tile должны быть определены в лямбда-функции одного вызова materialScope() верхнего уровня. Эти функции компонентов, такие как
primaryLayout()иtextEdgeButton(), являются функциями расширенияMaterialScopeи доступны только при вызове в этой области видимости получателя.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() ) } ) }
Слоты
В M3 расположение плиток использует подход, вдохновленный Compose, и задействует три отдельных слота . Сверху вниз они расположены следующим образом:
-
titleSlotобычно используется для основного заголовка или шапки страницы. -
mainSlotпредназначен для размещения основного контента. -
bottomSlot) часто используется для действий или дополнительной информации. Здесь же располагается боковая кнопка.

Содержимое каждого слота следующее:
-
titleSlot(необязательно): Обычно несколько слов, сгенерированных функциейtext(). -
mainSlot(обязательный): Компоненты, организованные в структуры, такие как строки , столбцы и группы кнопок . Эти компоненты также могут рекурсивно встраиваться друг в друга; например, столбец может содержать строки. -
bottomSlot(опционально): Обычно заполняется либо кнопкой, прилегающей к краю , либо текстовой меткой.
Поскольку плитки не прокручиваются, отсутствуют компоненты для постраничной навигации, прокрутки или обработки длинных списков контента. Необходимо следить за тем, чтобы контент оставался видимым при увеличении размера шрифта или удлинении текста из-за перевода.
Компоненты пользовательского интерфейса
Библиотека protolayout-material3 предоставляет большое количество компонентов, разработанных в соответствии со спецификациями Material 3 Expressive и рекомендациями по пользовательскому интерфейсу.
Кнопки
Кнопки в первую очередь ориентированы на действие . Они служат для запуска определенных действий. Содержимое каждой кнопки, например, значок или короткий текст, определяет действие.
- textButton() : кнопка с одним слотом для (короткого) текстового содержимого.
- iconButton() : кнопка с одним слотом для представления значка.
- avatarButton() : кнопка-аватар в форме таблетки, предоставляющая до трех слотов для размещения контента, представляющего собой вертикально расположенные метки и дополнительные метки, а также изображение (аватар) рядом с ней.
- imageButton() : кликабельная кнопка-изображение, не предоставляющая дополнительных слотов, только само изображение (например,
backgroundImageв качестве фона). - compactButton() : компактная кнопка, предоставляющая до двух слотов для размещения горизонтально расположенного контента, представляющего собой значок и текст рядом с ним.
- button() : кнопка в форме таблетки, предоставляющая до трех слотов для размещения контента, представляющего собой вертикально расположенные метки и дополнительные метки, а также значок рядом с ней.
Краевые кнопки
Краевая кнопка — это специальная кнопка во всю ширину экрана часов, расположенная в нижней части круглого экрана и обозначающая наиболее важное действие на текущем плиточном экране.
- iconEdgeButton() : краевая кнопка, предоставляющая одно поле для размещения значка или аналогичного круглого небольшого контента.
- textEdgeButton() : краевая кнопка, предоставляющая одно поле для ввода текста или аналогичного длинного и широкого содержимого.
Карты
Карточки в первую очередь ориентированы на предоставление информации . Они отображают наборы связанных структурированных данных. Хотя можно создавать интерактивные карточки, обычно они показывают краткое изложение информации, на которое пользователь может нажать, чтобы увидеть более подробную информацию или выполнить связанное действие.
- titleCard() : заголовок, предлагающий от одного до трех слотов, обычно текстового типа.
- appCard() : карточка приложения, предлагающая до пяти слотов, обычно текстового формата.
- textDataCard() : информационная карта, предлагающая до трех вертикально расположенных слотов, обычно текстовых или цифровых.
- iconDataCard() : карточка данных, содержащая до трех вертикально расположенных слотов, обычно текстовых или цифровых, с иконкой.
- graphicDataCard() : графическая карточка данных, которая предоставляет слот для графических данных, таких как индикатор выполнения, и до двух вертикально расположенных слотов, обычно для текстовых описаний.
Показатели прогресса
- circularProgressIndicator() : отображает прогресс в достижении цели с помощью радиального элемента.
- segmentedCircularProgressIndicator() : отображает прогресс в достижении цели с помощью радиального элемента с различными этапами.
Элементы групповой компоновки
- buttonGroup() : компонент макета, который размещает свои дочерние элементы в горизонтальной последовательности.
- primaryLayout() : полноэкранный макет, представляющий собой предлагаемый стиль компоновки M3, который является адаптивным и учитывает размещение элементов, а также рекомендуемые поля и отступы.
Примените тему
В Material 3 Expressive цветовая система определяется 29 стандартными цветовыми ролями, организованными в шесть групп: основные, второстепенные, третичные, ошибки, поверхностные и контурные.

ColorScheme сопоставляет каждую из этих 29 ролей с соответствующим цветом, и, поскольку она является частью MaterialScope , а компоненты должны создаваться внутри неё, они автоматически берут цвета из схемы. Такой подход позволяет всем элементам пользовательского интерфейса автоматически соответствовать стандартам Material Design.
Чтобы пользователи могли выбирать между заданной вами цветовой схемой — например, отражающей фирменные цвета вашей компании — и схемой, предоставляемой системой (либо полученной из текущего циферблата пользователя, либо выбранной пользователем), инициализируйте MaterialScope следующим образом:
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. }
Если вы выберете этот вариант, укажите монохромный значок плитки, чтобы его можно было правильно отобразить для оптимальной видимости на любом фоне.
Чтобы ваши плитки отображались в заданной вами цветовой схеме, отключите поддержку динамического оформления, установив параметр allowDynamicTheme в false :
materialScope( context = context, deviceConfiguration = requestParams.deviceConfiguration, allowDynamicTheme = false, defaultColorScheme = myColorScheme ) { // myColorScheme is *always* used. }
Цвет
Каждый отдельный компонент использует подмножество из 29 цветовых ролей, определенных ColorScheme . Например, кнопки используют до четырех цветов, которые по умолчанию берутся из «основной» группы активной ColorScheme :
компонентный токен ButtonColors | роль ColorScheme |
|---|---|
| containerColor | начальный |
| iconColor | onPrimary |
| labelColor | onPrimary |
| secondaryLabelColor | onPrimary (opacity 0.8) |
Подробные инструкции по применению цвета в дизайне Wear OS см. в руководстве по цветовому оформлению .
Возможно, вам потребуется отклониться от стандартных цветовых токенов для определенных элементов пользовательского интерфейса. Например, вы можете захотеть, чтобы элемент textEdgeButton использовал цвета из группы «вторичные» или «третичные», а не из группы «основные», чтобы выделиться и обеспечить лучший контраст.
Цвета компонентов можно настроить несколькими способами:
Используйте вспомогательную функцию для предопределенных цветов. Вспомогательные функции, такие как
filledTonalButtonColors()позволяют применять стандартные стили кнопок для Material 3 Expressive. Эти функции создают предварительно настроенные экземплярыButtonColors, которые сопоставляют распространенные стили, такие как «заполненный», «тональный» или «контурный», с соответствующими ролями из активнойColorSchemeвMaterialScope. Это позволяет применять согласованные стили без ручного определения каждого цвета для распространенных типов кнопок.textEdgeButton( colors = filledButtonColors(), // default /* OR colors = filledTonalButtonColors() */ /* OR colors = filledVariantButtonColors() */ // ... other parameters )
Для карточек используйте эквивалентные функции семейства
filledCardColors().Вы также можете изменить объект
ButtonColorsвозвращаемый вспомогательными функциями, используя их методcopy()если вам нужно изменить только один или два токена:textEdgeButton( colors = filledButtonColors() .copy( containerColor = colorScheme.tertiary, labelColor = colorScheme.onTertiary ), // ... other parameters )
Явно укажите роли для замены цветов. Создайте собственный объект
ButtonColorsи передайте его компоненту. Для карточек используйте эквивалентный объектCardColors.textEdgeButton( colors = ButtonColors( // the materialScope makes colorScheme available containerColor = colorScheme.secondary, iconColor = colorScheme.secondaryDim, labelColor = colorScheme.onSecondary, secondaryLabelColor = colorScheme.onSecondary ), // ... other parameters )
Указывайте фиксированные цвета (используйте с осторожностью). Хотя обычно рекомендуется указывать цвета по их семантической роли (например,
colorScheme.primary), вы также можете указывать прямые значения цветов. Этот подход следует использовать с осторожностью, поскольку он может привести к несоответствиям с общей темой, особенно если тема динамически меняется.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 )
Типография
Для получения более подробной информации об эффективном использовании типографики в ваших проектах, см. руководство по типографическому дизайну .
Для обеспечения визуальной согласованности на платформе Wear OS и оптимизации производительности весь текст на плитках отображается с использованием системного шрифта. То есть плитки не поддерживают пользовательские шрифты. В Wear OS 6 и выше это шрифт, специфичный для производителя оборудования. В большинстве случаев это будет вариативный шрифт, обеспечивающий более выразительный интерфейс и более детальный контроль.
Для создания стиля текста обычно используется метод text() в сочетании с типографическими константами. Этот компонент позволяет использовать предопределенные типографические роли в Material 3 Expressive, что помогает вашему элементу соответствовать установленным типографическим стандартам читаемости и иерархии. Библиотека предлагает набор из 18 семантических типографических констант , таких как BODY_MEDIUM . Эти константы также влияют на оси шрифта, помимо размера.
text( text = "Hello, World!".layoutString, typography = BODY_MEDIUM, )
Для более полного контроля вы можете задать дополнительные параметры . В Wear OS 6 и более поздних версиях, скорее всего, будет использоваться переменный шрифт, который вы можете изменять по осям курсив, толщина , ширина и округлость . Вы можете управлять этими осями с помощью параметра 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) ), )
Наконец, если вам необходимо контролировать размер или межбуквенное расстояние (что не рекомендуется), используйте basicText() вместо text() и сформируйте значение для свойства fontStyle с помощью fontStyle( ).
Форма и поля
Вы можете изменить радиус скругления углов практически любого компонента, используя его свойство shape . Значения берутся из shapes объекта MaterialScope :
textButton( height = expand(), width = expand(), shape = shapes.medium, // OR another value like shapes.full colors = filledVariantButtonColors(), labelContent = { text("Hello, World!".layoutString) }, )
После изменения формы компонента, если вы считаете, что по краям экрана остается слишком много или слишком мало свободного пространства, отрегулируйте поля, используя параметр ` margin ` primaryLayout() :
primaryLayout( mainSlot = { textButton( shape = shapes.small, /* ... */ ) }, // margin constants defined in androidx.wear.protolayout.material3.PrimaryLayoutMargins margins = MAX_PRIMARY_LAYOUT_MARGIN, )
Арки
Поддерживаются следующие дочерние элементы контейнеров Arc :
-
ArcLine: отображает изогнутую линию вокруг дуги. -
ArcText: отображает изогнутый текст в дуге. -
ArcAdapter: отображает базовый элемент компоновки внутри дуги, нарисованный по касательной к дуге.
Для получения более подробной информации см. справочную документацию по каждому из типов элементов.
Модификаторы
К каждому доступному элементу макета можно дополнительно применить модификаторы. Используйте эти модификаторы для следующих целей:
- Измените визуальное оформление макета. Например, добавьте фон, рамку или отступы к элементу макета.
- Добавьте метаданные о макете. Например, добавьте модификатор семантики к элементу макета для использования программами чтения с экрана.
- Добавьте функциональность. Например, добавьте кликабельный модификатор к элементу макета, чтобы сделать ваш тайл интерактивным. Для получения дополнительной информации см. раздел «Взаимодействие с тайлами» .
Например, мы можем настроить внешний вид и метаданные Image по умолчанию, как показано в следующем примере кода:
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()
Спанблс
Spannable — это особый тип контейнера, который размещает элементы аналогично тексту. Это полезно, когда нужно применить разный стиль только к одной подстроке в большом блоке текста, что невозможно с элементом Text .
Контейнер Spannable заполняется дочерними элементами Span . Другие дочерние элементы или вложенные экземпляры Spannable не допускаются.
Существует два типа детей Span :
-
SpanText: отображает текст с определенным стилем. -
SpanImage: отображает изображение непосредственно рядом с текстом.
Например, вы можете выделить слово «world» курсивом в блоке «Hello world» и вставить изображение между словами, как показано в следующем примере кода:
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()
Работа с ресурсами
Плитки не имеют доступа к ресурсам вашего приложения. Это означает, что вы не можете передать идентификатор изображения Android элементу макета Image и ожидать, что он будет обработан. Вместо этого переопределите метод onTileResourcesRequest() и предоставьте все необходимые ресурсы вручную.
Существует два способа предоставления изображений в методе onTileResourcesRequest() :
- Предоставьте ресурс изображения, используя
setAndroidResourceByResId(). - Предоставьте динамическое изображение в виде
ByteArray, используяsetInlineResource().
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() )
Контрольный список изображений для предварительного просмотра плитки
Система отображает изображение предварительного просмотра плитки, указанное в манифесте приложения Android, в редакторе карусели плиток для добавления новой плитки. Этот редактор доступен как на устройствах Wear OS, так и в сопутствующем приложении для часов на телефонах.
Чтобы помочь пользователям максимально эффективно использовать это предварительное изображение, проверьте следующие характеристики вашего плитки:
- Отражает новейший дизайн . Предварительный просмотр должен точно отображать самый актуальный дизайн вашей плитки.
- Используются рекомендуемые размеры . Для обеспечения наилучшего качества отображения и удобства использования изображение предварительного просмотра должно иметь размеры 400x400 пикселей.
- Использует статическую цветовую тему . Используйте статическую цветовую тему плитки, а не динамическую.
- Включает значок приложения . Убедитесь, что значок вашего приложения отображается в верхней части изображения предварительного просмотра.
- Отображает состояние «загружено/вход в систему ». Предварительный просмотр должен отображать полностью функциональное состояние «загружено» или «вход в систему», избегая любого пустого или заглушечного контента.
- Используйте правила разрешения ресурсов для персонализации (необязательно). Рассмотрите возможность использования правил разрешения ресурсов Android для отображения предварительного просмотра, соответствующего размеру экрана устройства, языку или языковым настройкам. Это особенно полезно, если внешний вид вашего плитки различается на разных устройствах.