Показывать динамические обновления в плитках

Начиная с версии Tiles 1.2, вы можете передавать обновления данных платформы с помощью динамических выражений . Затем вы можете связать эти обновления с анимацией в ваших тайлах. Ваше приложение получает обновления этого значения каждую секунду.

Использование динамических выражений позволяет избежать обновления всего элемента при изменении его содержимого. Для создания более привлекательного интерфейса используйте анимацию динамических объектов.

Связывайте динамические выражения с источниками данных.

Пространства имен androidx.wear.protolayout и androidx.wear.protolayout.material содержат множество классов, поля которых принимают динамические выражения. В качестве примеров можно привести следующие:

Чтобы использовать динамическое выражение в качестве возможного значения для элемента в вашем блоке, используйте соответствующий динамический тип свойства *Prop для этого элемента и передайте источник данных в метод setDynamicValue() класса-конструктора этого динамического типа свойства.

Плитки поддерживают следующие динамические типы свойств:

  • Для линейных размеров, измеряемых в пикселях, не зависящих от дисплея, используйте DimensionBuilders.DpProp .
  • Для угловых размеров, измеряемых в градусах, используйте DimensionBuilders.DegreesProp .
  • Для строковых значений используйте TypeBuilders.StringProp .
  • Для указания цветовых значений используйте ColorBuilders.ColorProp .
  • Для значений с плавающей запятой используйте TypeBuilders.FloatProp .

При использовании динамического выражения, влияющего на физические размеры — любое значение в плитке, кроме цвета, — необходимо также указать набор связанных ограничений, например, формат строки. Эти ограничения позволяют системному рендереру определить максимальный объем пространства, который значение может занимать в вашей плитке. Обычно эти ограничения задаются на уровне элемента, а не на уровне динамического выражения, путем вызова метода, начинающегося с setLayoutConstraintsForDynamic* .

Следующий фрагмент кода показывает, как отображать обновления частоты сердечных сокращений с использованием 3 цифр, с резервным значением -- :

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(),
                        TypeBuilders.StringLayoutConstraint.Builder("000").build(),
                    )
                        .build()
                )
            )
            .build()
    )

Используйте небольшое количество выражений в пределах одного блока.

Wear OS ограничивает количество выражений, которые может содержать один элемент интерфейса. Если элемент интерфейса содержит слишком много динамических выражений, динамические значения игнорируются, и система переключается на статические значения, которые вы указываете для соответствующих типов динамических свойств.

Объединить динамические данные в объект состояния.

Вы можете объединить последние обновления из источников данных в состояние , которое затем передаете своему плитке для отображения значений.

Чтобы использовать информацию о состоянии в ваших тайлах, выполните следующие шаги:

  1. Создайте набор ключей, представляющих различные значения состояния вашего элемента. В этом примере создаются ключи для водозабора и заметки qqq:

    companion object {
        val KEY_WATER_INTAKE = intAppDataKey("key_water_intake")
        val KEY_NOTE = stringAppDataKey("key_note")
    }

  2. В вашей реализации метода onTileRequest() вызовите setState() и установите начальные соответствия между каждым ключом и конкретным динамическим значением данных:

    override fun onTileRequest(
        requestParams: RequestBuilders.TileRequest
    ): ListenableFuture<Tile?> {
        // If the tile hasn't had any state set yet, use the default values
        val state =
            if (requestParams.currentState.keyToValueMapping.isNotEmpty())
                requestParams.currentState
            else
                StateBuilders.State.Builder()
                    .setStateMap(
                        dynamicDataMapOf(
                            KEY_WATER_INTAKE mapTo 200,
                            KEY_NOTE mapTo "Good"
                        )
                    )
                    .build()
    
        return Futures.immediateFuture(
            Tile.Builder()
                // Set resources, timeline, and other tile properties.
                .setState(state)
                .build()
        )
    }

  3. При создании макета в том месте, где вы хотите отобразить данные из состояния, используйте объект типа Dynamic* . Вы также можете вызвать animate() для отображения анимации от предыдущего значения к текущему:

    val waterIntakeValue =
        DynamicBuilders.DynamicInt32.from(KEY_WATER_INTAKE)

  4. При необходимости вы также можете обновить состояние новыми значениями. Это может быть частью LoadAction для плитки.

    В этом примере значение потребления воды обновлено до 400 :

    val loadAction =
        loadAction(
            dynamicDataMapOf(
                KEY_WATER_INTAKE mapTo 400,
                KEY_NOTE mapTo "Outstanding"
            )
        )

{% verbatim %} {% endverbatim %} {% verbatim %} {% endverbatim %}