Na versão 1.2 da API Tiles e mais recentes, é possível transmitir atualizações de dados da plataforma usando expressões dinâmicas. Você também pode associar essas atualizações a animações nos blocos. Seu app recebe atualizações para esse valor a cada segundo.
Com as expressões dinâmicas, você não precisa atualizar todo o Bloco quando o conteúdo dele mudar. Para criar uma experiência mais envolvente nos Blocos, anime esses objetos dinâmicos.
Associar expressões dinâmicas a fontes de dados
Os namespaces androidx.wear.protolayout
e androidx.wear.protolayout.material
contêm muitas classes com campos que aceitam expressões dinâmicas.
Entre os exemplos estão os seguintes:
- Diversos valores de comprimento, incluindo o comprimento de um objeto
Arc
e de um objetoCircularProgressIndicator
. - Qualquer cor, como a cor do conteúdo de um objeto
Button
. - Muitos valores de string, incluindo o conteúdo de um objeto
Text
, o conteúdo de um objetoLayoutElementsBuilders.Text
e a descrição de conteúdo de um objetoCircularProgressIndicator
.
Para usar uma expressão dinâmica como um valor possível de um elemento no seu Bloco, use
o tipo de propriedade dinâmica *Prop
correspondente do elemento e transmita a fonte
de dados para o método setDynamicValue()
da classe de builder do tipo de propriedade
dinâmica.
Os Blocos oferecem suporte a estes tipos de propriedade dinâmica:
- Para dimensões lineares, medidas em pixels independentes da tela, use
DimensionBuilders.DpProp
. - Para dimensões angulares, medidas em graus, use
DimensionBuilders.DegreesProp
. - Para valores de string, use
TypeBuilders.StringProp
. - Para valores de cor, use
ColorBuilders.ColorProp
. - Para valores de ponto flutuante, use
TypeBuilders.FloatProp
.
Ao usar uma expressão dinâmica que afeta dimensões físicas (qualquer valor em
um Bloco, exceto cor), também é necessário especificar um conjunto de restrições relacionadas, como
um formato de string. Essas restrições permitem que o renderizador do sistema determine a
quantidade máxima de espaço que um valor pode ocupar no Bloco. Normalmente,
essas restrições são especificadas no nível do elemento, não no da expressão
dinâmica, chamando um método que comece com setLayoutConstraintsForDynamic*
.
O snippet de código abaixo mostra como exibir atualizações de frequência cardíaca usando três
dígitos, com um valor substituto 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() ); }
Usar um número pequeno de expressões em um único Bloco
O Wear OS limita o número de expressões que um único Bloco pode ter. Se um Bloco tiver muitas expressões dinâmicas no total, os valores dinâmicos serão ignorados, e o sistema voltará aos valores estáticos fornecidos aos respectivos tipos de propriedade dinâmica.
Você pode adicionar com segurança o conjunto de expressões abaixo a um Bloco, porque não há muitas expressões no total e o Bloco se funcionará corretamente:
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");
No entanto, este Bloco pode ter muitas expressões:
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) ); }
Consolidar dados dinâmicos em um objeto de estado
É possível consolidar o conjunto mais recente de atualizações das fontes de dados em um estado, que você transmite ao Bloco para renderizar o valor.
Para usar informações de estado nos seus Blocos, siga estas etapas:
Estabeleça um conjunto de chaves que represente os diferentes valores do estado do Bloco. Este exemplo cria chaves para o consumo de água e uma observação:
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");
Na implementação de
onTileRequest()
, chamesetState()
e estabeleça mapeamentos iniciais de cada chave para um determinado valor de dados dinâmicos: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() ); }
Ao criar o layout, em um lugar em que você quer mostrar esses dados do estado, use um objeto do tipo
Dynamic*
. Você também pode chamaranimate()
para mostrar uma animação de transição do valor anterior para o atual:Kotlin
DynamicInt32.from(KEY_WATER_INTAKE).animate()
Java
DynamicInt32.from(KEY_WATER_INTAKE).animate();
Quando necessário, atualize também o estado com novos valores. Isso pode fazer parte da
LoadAction
de um Bloco.Neste exemplo, o valor de entrada de água é atualizado para
400
:Kotlin
state.addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400))
Java
state.addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400));
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Migrar para namespaces ProtoLayout
- Começar a usar Blocos
- Outras considerações