A partir de Tiles 1.2, puedes transmitir actualizaciones de datos de la plataforma usando expresiones dinámicas. Luego, puedes asociar esas actualizaciones con animaciones en tus tarjetas. Tu app recibe actualizaciones de este valor cada segundo.
Con las expresiones dinámicas, no necesitas actualizar toda la tarjeta cuando cambia su contenido. Para crear una experiencia más atractiva en tus tarjetas, anima esos objetos dinámicos.
Cómo asociar expresiones dinámicas con fuentes de datos
Los espacios de nombres androidx.wear.protolayout
y androidx.wear.protolayout.material
contienen muchas clases cuyos campos aceptan expresiones dinámicas.
Entre los ejemplos, se incluyen los siguientes:
- Varios valores de longitud, incluida la longitud de un objeto
Arc
y la longitud de un objetoCircularProgressIndicator
- Cualquier color, como el color del contenido de un objeto
Button
- Muchos valores de cadenas, incluido el contenido de un objeto
Text
, el contenido de un objetoLayoutElementsBuilders.Text
y la descripción del contenido de un objetoCircularProgressIndicator
Si deseas usar una expresión dinámica como un valor posible para un elemento de tu tarjeta, usa el tipo de propiedad dinámica *Prop
correspondiente del elemento y pasa la fuente de datos al método setDynamicValue()
de la clase de compilador del tipo de propiedad dinámica.
Las tarjetas admiten los siguientes tipos de propiedades dinámicas:
- Para las dimensiones lineales, medidas en píxeles independientes de la pantalla, usa
DimensionBuilders.DpProp
. - Para las dimensiones angulares, medidas en grados, usa
DimensionBuilders.DegreesProp
. - Para los valores de cadena, usa
TypeBuilders.StringProp
. - Para los valores de color, usa
ColorBuilders.ColorProp
. - Para los valores de punto flotante, usa
TypeBuilders.FloatProp
.
Cuando usas una expresión dinámica que afecta las dimensiones físicas (cualquier valor en una tarjeta, excepto el color), también debes especificar un conjunto de restricciones relacionadas, como un formato de cadena. Estas restricciones permiten que el procesador del sistema determine la cantidad máxima de espacio que un valor podría ocupar en tu tarjeta. Por lo general, debes especificar estas restricciones a nivel del elemento, no a nivel de la expresión dinámica, llamando a un método que comience con setLayoutConstraintsForDynamic*
.
En el siguiente fragmento de código, se indica cómo mostrar las actualizaciones de una frecuencia cardíaca usando 3 dígitos, con un valor de resguardo de --
:
Kotlin
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() )
Java
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() ); }
Cómo usar una pequeña cantidad de expresiones en una sola tarjeta
Wear OS establece un límite para la cantidad de expresiones que puede tener una sola tarjeta. Si una tarjeta contiene demasiadas expresiones dinámicas en total, se ignoran los valores dinámicos y el sistema recurre a los valores estáticos que proporcionas a los tipos de propiedades dinámicas respectivos.
Puedes agregar de forma segura el siguiente conjunto de expresiones a una tarjeta, ya que no hay muchas expresiones en total. Por lo tanto, la tarjeta se comporta correctamente:
Kotlin
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")
Java
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");
Sin embargo, esta tarjeta podría tener demasiadas expresiones:
Kotlin
// 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) ) }
Java
// 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) ); }
Cómo consolidar datos dinámicos en un objeto de estado
Puedes consolidar el conjunto más reciente de actualizaciones de fuentes de datos en un estado, el cual pasas a tu tarjeta para la renderización de valores.
Para usar información de estado en tus tarjetas, realiza estos pasos:
Establece un conjunto de claves que representen los diferentes valores del estado de tu tarjeta. En este ejemplo, se crean claves para el consumo de agua y una nota:
Kotlin
companion object { val KEY_WATER_INTAKE = AppDataKey<DynamicInt32>("water_intake") val KEY_NOTE = AppDataKey<DynamicString>("note") }
Java
private static final AppDataKey<DynamicInt32> KEY_WATER_INTAKE = new AppDataKey<DynamicInt32>("water_intake"); private static final AppDataKey<DynamicString> KEY_NOTE = new AppDataKey<DynamicString>("note");
En tu implementación de
onTileRequest()
, llama asetState()
y establece asignaciones iniciales de cada clave a un valor de datos dinámico en particular:Kotlin
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() )
Java
@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() ); }
Cuando crees tu diseño, en un lugar en el que desees mostrar estos datos de estado, usa un objeto de tipo
Dynamic*
. También puedes llamar aanimate()
para mostrar una animación del valor anterior al valor actual:Kotlin
DynamicInt32.from(KEY_WATER_INTAKE).animate()
Java
DynamicInt32.from(KEY_WATER_INTAKE).animate();
Cuando sea necesario, también puedes actualizar el estado con valores nuevos. Puede ser parte del elemento
LoadAction
de una tarjeta.En este ejemplo, el valor de consumo de agua se actualiza a
400
:Kotlin
state.addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400))
Java
state.addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400));
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Cómo migrar a espacios de nombres de ProtoLayout
- Cómo comenzar a usar tarjetas
- Otras consideraciones