Начиная с версии Tiles 1.2, вы можете осуществлять потоковую передачу обновлений данных платформы с помощью динамических выражений . Затем вы можете связать эти обновления с анимацией на плитках. Ваше приложение получает обновления этого значения каждую секунду.
Используя динамические выражения, вам не нужно обновлять всю плитку при изменении ее содержимого. Чтобы сделать плитки более привлекательными, анимируйте эти динамические объекты.
Связывание динамических выражений с источниками данных
Пространства имен androidx.wear.protolayout
и androidx.wear.protolayout.material
содержат множество классов, поля которых принимают динамические выражения. Несколько примеров включают следующее:
- Несколько значений длины, включая длину объекта
Arc
и длину объектаCircularProgressIndicator
. - Любой цвет, например цвет содержимого объекта
Button
. - Множество строковых значений, включая содержимое объекта
Text
, содержимое объектаLayoutElementsBuilders.Text
и описание содержимого объектаCircularProgressIndicator
.
Чтобы использовать динамическое выражение в качестве возможного значения для элемента в плитке, используйте соответствующий тип динамического свойства *Prop
элемента и передайте источник данных методу setDynamicValue()
класса-построителя динамического типа свойства.
Плитки поддерживают следующие типы динамических свойств:
- Для линейных размеров, измеренных в независимых от дисплея пикселях, используйте
DimensionBuilders.DpProp
. - Для угловых размеров, измеряемых в градусах, используйте
DimensionBuilders.DegreesProp
. - Для строковых значений используйте
TypeBuilders.StringProp
. - Для значений цвета используйте
ColorBuilders.ColorProp
. - Для значений с плавающей запятой используйте
TypeBuilders.FloatProp
.
При использовании динамического выражения, влияющего на физические размеры (любое значение в плитке, кроме цвета), необходимо также указать набор связанных ограничений, например строковый формат. Эти ограничения позволяют средству визуализации системы определить максимальный объем пространства, которое значение может занимать внутри плитки. Обычно эти ограничения указываются на уровне элемента, а не на уровне динамического выражения, путем вызова метода, который начинается с setLayoutConstraintsForDynamic*
.
В следующем фрагменте кода показано, как отображать обновления частоты пульса с помощью 3 цифр с резервным значением --
:
Котлин
import androidx.wear.protolayout.material.Text public override fun onTileRequest(requestParams: RequestBuilders.TileRequest) = Futures.immediateFuture(Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes .setTileTimeline(Timeline.fromLayoutElement( Text.Builder(this, TypeBuilders.StringProp.Builder("--") .setDynamicValue(PlatformHealthSources.heartRateBpm() .format() .concat(DynamicBuilders.DynamicString.constant(" bpm"))) .build(), StringLayoutConstraint.Builder("000") .build() ).build() ) ).build() )
Ява
import androidx.wear.protolayout.material.Text; @Override protected ListenableFuture<Tile> onTileRequest( @NonNull TileRequest requestParams ) { return Futures.immediateFuture(new Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes .setTileTimeline(Timeline.fromLayoutElement( new Text.Builder( this, new TypeBuilders.StringProp.Builder("--") .setDynamicValue(PlatformHealthSources.heartRateBpm() .format() .concat(DynamicBuilders.DynamicString.constant(" bpm"))) .build(), new StringLayoutConstraint.Builder("000") .build() ).build()) ).build() ); }
Используйте небольшое количество выражений в пределах одной плитки.
Wear OS накладывает ограничение на количество выражений, которые может иметь одна плитка. Если плитка содержит слишком много динамических выражений, динамические значения игнорируются, и система возвращается к статическим значениям, которые вы предоставляете соответствующим типам динамических свойств.
Вы можете смело добавить в плитку следующий набор выражений, так как всего выражений не так много. Следовательно, плитка ведет себя корректно:
Котлин
val personHealthInfo = DynamicString.constant("This person has walked ") .concat(PlatformHealthSources.dailySteps() .div(1000) .format()) .concat("thousands of steps and has a current heart rate ") .concat(PlatformHealthSources.heartRateBpm() .format()) .concat(" beats per minute")
Ява
DynamicString personHealthInfo = DynamicString.constant("This person has walked ") .concat(PlatformHealthSources.dailySteps() .div(1000) .format()) .concat("thousands of steps and has a current heart rate ") .concat(PlatformHealthSources.heartRateBpm() .format()) .concat(" beats per minute");
Однако на этой плитке может быть слишком много выражений:
Котлин
// Note that this template is applied as many times as the loop iterates. // The system doesn't reuse dynamic expressions. val dynamicStringTemplate = PlatformHealthSources.dailySteps() .div(1000) .format() for (person in people) { // SomeProperty .setDynamicValue( DynamicBuilders.DynamicString.constant("Steps for ") .concat(person) .concat(" are ") .concat(dynamicStringTemplate) ) }
Ява
// Note that this template is applied as many times as the loop iterates. // The system doesn't reuse dynamic expressions. DynamicString dynamicStringTemplate = PlatformHealthSources.dailySteps() .div(1000) .format(); for (int i = 0; i < people.size(); i++) { // SomeProperty .setDynamicValue( DynamicBuilders.DynamicString.constant("Steps for ") .concat(people[i]) .concat(" are ") .concat(dynamicStringTemplate) ); }
Консолидация динамических данных в объект состояния
Вы можете объединить последний набор обновлений из источников данных в состояние , которое вы передаете на свою плитку для рендеринга значений.
Чтобы использовать информацию о состоянии в плитках, выполните следующие действия:
Установите набор ключей, которые представляют различные значения состояния вашей плитки. В этом примере создаются ключи для забора воды и примечание:
Котлин
companion object { val KEY_WATER_INTAKE = AppDataKey<DynamicInt32>("water_intake") val KEY_NOTE = AppDataKey<DynamicString>("note") }
Ява
private static final AppDataKey<DynamicInt32> KEY_WATER_INTAKE = new AppDataKey<DynamicInt32>("water_intake"); private static final AppDataKey<DynamicString> KEY_NOTE = new AppDataKey<DynamicString>("note");
В вашей реализации
onTileRequest()
вызовитеsetState()
и установите начальные сопоставления каждого ключа с конкретным значением динамических данных:Котлин
override fun onTileRequest(requestParams: TileRequest): ListenableFuture<Tile> { val state = State.Builder() .addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(200)) .addKeyToValueMapping(KEY_NOTE, DynamicDataBuilders.DynamicDataValue.fromString("Note about day")) .build() // ... return Futures.immediateFuture(Tile.Builder() // Set resources, timeline, and other tile properties. .setState(state) .build() )
Ява
@Override protected ListenableFuture<Tile> onTileRequest( ListenableFuture<Tile> { State state = new State.Builder() .addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(200)) .addKeyToValueMapping(KEY_NOTE, DynamicDataBuilders.DynamicDataValue.fromString("Note about day")) .build(); // ... return Futures.immediateFuture(Tile.Builder() // Set resources, timeline, and other tile properties. .setState(state) .build() ); }
При создании макета в том месте, где вы хотите отобразить эти данные из состояния, используйте объект типа
Dynamic*
. Вы также можете вызватьanimate()
чтобы показать анимацию от предыдущего значения до текущего значения:Котлин
DynamicInt32.from(KEY_WATER_INTAKE).animate()
Ява
DynamicInt32.from(KEY_WATER_INTAKE).animate();
При необходимости вы также можете обновить состояние, добавив новые значения. Это может быть частью
LoadAction
плитки.В этом примере значение водозабора обновляется до
400
:Котлин
val loadAction = LoadAction.Builder() .setRequestState( State.Builder() .addKeyToValueMapping( KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400) ) .build() ) .build()
Ява
LoadAction loadAction = new LoadAction.Builder() .setRequestState( new State.Builder() .addKeyToValueMapping( KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400) ).build() ).build();
Рекомендуется для вас
- Примечание. Текст ссылки отображается, когда JavaScript отключен.
- Миграция в пространства имен ProtoLayout
- Начало работы с плиткой
- Другие соображения