Чтобы начать предоставлять плитки из вашего приложения, включите следующие зависимости в файл build.gradle
вашего приложения.
классный
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" }
Котлин
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") }
Создать плитку
Чтобы предоставить плитку из вашего приложения, создайте класс, расширяющий TileService
, и реализуйте методы, как показано в следующем примере кода:
Котлин
// 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() ) }
Ява
// 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() ); } }
Затем добавьте службу в тег <application>
вашего файла AndroidManifest.xml
.
<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>
Фильтр разрешений и намерений регистрирует эту службу в качестве поставщика плиток.
Значок, метка и описание отображаются пользователю при настройке плиток на телефоне или часах.
Используйте тег метаданных предварительного просмотра, чтобы отобразить предварительный просмотр плитки при ее настройке на телефоне.
Обзор жизненного цикла службы плиток
После того как вы создали и объявили свой TileService
в манифесте приложения, вы можете реагировать на изменения состояния сервиса плиток.
TileService
— это привязанный сервис . Ваш TileService
привязывается в результате запроса вашего приложения или если системе необходимо взаимодействовать с ним. Типичный жизненный цикл привязанного сервиса содержит следующие четыре метода обратного вызова: onCreate()
, onBind()
, onUnbind()
и onDestroy()
. Система вызывает эти методы каждый раз, когда служба переходит в новую фазу жизненного цикла.
Помимо обратных вызовов, управляющих жизненным циклом привязанного сервиса, вы можете реализовать другие методы, специфичные для жизненного цикла TileService
. Все службы плиток должны реализовывать onTileRequest()
и onTileResourcesRequest()
чтобы отвечать на запросы обновлений от системы.
onTileAddEvent()
: система вызывает этот метод только тогда, когда пользователь добавляет плитку в первый раз, а также если пользователь удаляет и добавляет плитку снова. Это лучшее время для однократной инициализации.onTileAddEvent()
вызывается только при перенастройке набора плиток, а не всякий раз, когда плитка создается системой. Например, когда устройство перезагружается или включается,onTileAddEvent()
не вызывается для уже добавленных плиток. Вместо этого вы можете использоватьgetActiveTilesAsync()
чтобы получить снимок того, какие принадлежащие вам плитки активны.onTileRemoveEvent()
: система вызывает этот метод, только если пользователь удаляет вашу плитку.onTileEnterEvent()
: система вызывает этот метод, когда плитка, предоставленная этим провайдером, появляется на экране.onTileLeaveEvent()
: система вызывает этот метод, когда плитка, предоставленная этим провайдером, выходит из поля зрения на экране.onTileRequest()
: система вызывает этот метод, когда система запрашивает новую временную шкалу у этого провайдера.onTileResourcesRequest()
: система вызывает этот метод, когда система запрашивает пакет ресурсов у этого поставщика. Это может произойти при первой загрузке плитки или при изменении версии ресурса.
Запросить, какие плитки активны
Активные плитки — это плитки, добавленные для отображения на часах. Используйте статический метод TileService
getActiveTilesAsync()
чтобы узнать, какие плитки , принадлежащие вашему приложению, активны.
Создать пользовательский интерфейс для плиток
Компоновка плитки записывается с использованием шаблона строителя. Макет плитки построен как дерево, состоящее из контейнеров макета и основных элементов макета. Каждый элемент макета имеет свойства, которые вы можете установить с помощью различных методов установки.
Основные элементы макета
Вместе с компонентами Material поддерживаются следующие визуальные элементы из библиотеки protolayout
:
-
Text
: отображает строку текста, при необходимости перенося ее. -
Image
: отображает изображение. -
Spacer
: обеспечивает заполнение между элементами или может выступать в качестве разделителя, когда вы устанавливаете цвет фона.
Компоненты материала
В дополнение к базовым элементам библиотека protolayout-material
предоставляет компоненты, которые обеспечивают дизайн плитки в соответствии с рекомендациями пользовательского интерфейса Material Design.
-
Button
: кликабельный круглый компонент, содержащий значок. Chip
: кликабельный компонент в форме стадиона, содержащий до двух строк текста и дополнительный значок.CompactChip
: кликабельный компонент в форме стадиона, предназначенный для хранения строки текста.TitleChip
: кликабельный компонент в форме стадиона, похожий наChip
, но с большей высотой для размещения текста заголовка.CircularProgressIndicator
: круговой индикатор прогресса, который можно разместить внутриEdgeContentLayout
для отображения прогресса по краям экрана.
Контейнеры макета
Наряду с макетами материалов поддерживаются следующие контейнеры:
-
Row
: размещает дочерние элементы горизонтально, один за другим. -
Column
: размещает дочерние элементы вертикально, один за другим. -
Box
: накладывает дочерние элементы друг на друга. -
Arc
: размещает дочерние элементы по кругу. -
Spannable
: применяет определенныеFontStyles
к разделам текста вместе с чередованием текста и изображений. Для получения дополнительной информации см. Spannables .
Каждый контейнер может содержать одного или нескольких дочерних элементов, которые сами по себе также могут быть контейнерами. Например, Column
может содержать несколько дочерних элементов Row
, что приводит к созданию макета, напоминающего сетку.
Например, плитка с макетом-контейнером и двумя дочерними элементами макета может выглядеть так:
Котлин
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()
Ява
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(); }
Макеты материалов
В дополнение к базовым макетам библиотека protolayout-material
предоставляет несколько самостоятельных макетов, предназначенных для размещения элементов в определенных «слотах».
PrimaryLayout
: размещает одно основное действиеCompactChip
внизу, а содержимое центрирует над ним.MultiSlotLayout
: позиционирует первичные и вторичные метки с необязательным содержимым между ними и дополнительнымCompactChip
внизу.MultiButtonLayout
: позиционирует набор кнопок, расположенных в соответствии с рекомендациями по материалам.EdgeContentLayout
: размещает содержимое по краю экрана, напримерCircularProgressIndicator
. При использовании этого макета к содержимому внутри него автоматически применяются соответствующие поля и отступы.
Дуги
Поддерживаются следующие дочерние элементы контейнера 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)).build()) .setPadding(Padding.Builder().setStart(dp(12f)).build()) .setSemantics(Semantics.builder() .setContentDescription("Image description") .build() ).build() ).build()
Ява
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(); }
Спаннаблес
Spannable
— это особый тип контейнера, в котором элементы размещаются аналогично тексту. Это полезно, когда вы хотите применить другой стиль только к одной подстроке в большом блоке текста, что невозможно с элементом Text
.
Контейнер Spannable
заполняется дочерними элементами Span
. Другие дочерние элементы или вложенные экземпляры Spannable
не допускаются.
Есть два типа детей Span
:
-
SpanText
: отображает текст в определенном стиле. -
SpanImage
: отображает изображение вместе с текстом.
Например, вы можете выделить слово «мир» курсивом на плитке «Привет, мир» и вставить изображение между словами, как показано в следующем примере кода:
Котлин
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()
Ява
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(); }
Работа с ресурсами
Плитки не имеют доступа ни к каким ресурсам вашего приложения. Это означает, что вы не можете передать идентификатор изображения Android элементу макета Image
и ожидать его разрешения. Вместо этого переопределите метод onTileResourcesRequest()
и предоставьте все ресурсы вручную.
Существует два способа предоставления изображений в методе onTileResourcesRequest()
:
- Предоставьте доступный для рисования ресурс, используя
setAndroidResourceByResId()
. - Предоставьте динамическое изображение в виде
ByteArray
, используяsetInlineResource()
.
Котлин
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() )
Ява
@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() ); }
Рекомендуется для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Миграция в пространства имен ProtoLayout
-
ConstraintLayout
в Compose - Создавайте собственные плитки быстрых настроек для своего приложения.