Начиная с версии 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()
чтобы показать анимацию от предыдущего значения до текущего значения:При необходимости вы также можете обновить состояние, добавив новые значения. Это может быть частью
LoadAction
плитки.В этом примере значение водозабора обновляется до
400
:
Пока рекомендаций нет.
Попытайтесь войти в свой аккаунт Google.