Od wersji 1.2 kafelków możesz przesyłać strumieniowo aktualizacje danych platformy za pomocą wyrażeń dynamicznych. Możesz powiązać te aktualizacje z animacjami w kafelkach. Aplikacja aktualizuje tę wartość co sekundę.
Stosując wyrażenia dynamiczne, nie musisz odświeżać całego kafelka, gdy zmieni się jego zawartość. Aby zwiększyć atrakcyjność kafelków, możesz je animować.
Powiąż wyrażenia dynamiczne ze źródłami danych
Przestrzenie nazw androidx.wear.protolayout
i androidx.wear.protolayout.material
zawierają wiele klas, których pola akceptują wyrażenia dynamiczne.
Oto kilka przykładów:
- Kilku wartości długości, w tym długość obiektu
Arc
i długość obiektuCircularProgressIndicator
. - Dowolny kolor, na przykład kolor treści obiektu
Button
. - Wiele wartości ciągów znaków, w tym zawartość obiektu
Text
, zawartość obiektuLayoutElementsBuilders.Text
i opis treści obiektuCircularProgressIndicator
.
Aby użyć wyrażenia dynamicznego jako możliwej wartości elementu w kafelku, użyj odpowiedniego typu właściwości dynamicznej *Prop
dla tego elementu i przekaż źródło danych do metody setDynamicValue()
klasy konstruktora usługi dynamicznej.
Kafelki obsługują te typy właściwości dynamicznych:
- W przypadku wymiarów liniowych mierzonych w pikselach niezależnych od wyświetlania użyj danych
DimensionBuilders.DpProp
. - W przypadku wymiarów kątowych mierzonych w stopniach użyj wartości
DimensionBuilders.DegreesProp
. - Jako wartości ciągów znaków użyj
TypeBuilders.StringProp
. - Jako wartości kolorów użyj
ColorBuilders.ColorProp
. - W przypadku wartości zmiennoprzecinkowych użyj
TypeBuilders.FloatProp
.
Gdy używasz wyrażenia dynamicznego, które ma wpływ na wymiary fizyczne – dowolną wartość w kafelku oprócz koloru – musisz też określić zestaw powiązanych ograniczeń, np. format ciągu znaków. Te ograniczenia pozwalają mechanizmowi renderowania systemu określić maksymalną ilość miejsca, jaką dana wartość może zająć w kafelku. Zazwyczaj te ograniczenia określa się na poziomie elementu, a nie wyrażenia dynamicznego, wywołując metodę zaczynającą się od setLayoutConstraintsForDynamic*
.
Ten fragment kodu pokazuje, jak wyświetlić aktualizacje tętna za pomocą 3 cyfr z wartością zastępczą --
:
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() ); }
Używaj małej liczby wyrażeń w jednym kafelku
W Wear OS ograniczony jest limit liczby wyrażeń, które może zawierać 1 kafelek. Jeśli kafelek zawiera zbyt wiele wszystkich wyrażeń dynamicznych, wartości dynamiczne są ignorowane, a system przełącza się na wartości statyczne, które podasz odpowiednim typom właściwości dynamicznych.
Możesz bezpiecznie dodać do kafelka poniższy zestaw wyrażeń, ponieważ nie ma zbyt wielu wyrażeń. W związku z tym kafelek działa prawidłowo:
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");
Ten kafelek może mieć jednak zbyt wiele wyrażeń:
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) ); }
Skonsoliduj dane dynamiczne w obiekcie stanu
Możesz skonsolidować najnowszy zestaw aktualizacji ze źródeł danych w stan, który przekazujesz do kafelka do renderowania wartości.
Aby użyć informacji o stanie w kafelkach, wykonaj te czynności:
Utwórz zestaw kluczy reprezentujących różne wartości stanu kafelka. W tym przykładzie tworzymy klucze do picia wody i nutę:
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");
W swojej implementacji funkcji
onTileRequest()
wywołajsetState()
i ustal początkowe mapowania każdego klucza na konkretną dynamiczną wartość danych: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() ); }
Podczas tworzenia układu w miejscu, w którym chcesz pokazywać te dane ze stanu, użyj obiektu typu
Dynamic*
. Możesz też wywołaćanimate()
, by wyświetlić animację z poprzedniej wartości do aktualnej:Kotlin
DynamicInt32.from(KEY_WATER_INTAKE).animate()
Java
DynamicInt32.from(KEY_WATER_INTAKE).animate();
W razie potrzeby możesz też zaktualizować stan o nowe wartości. Może to być część
LoadAction
kafelka.W tym przykładzie wartość spożycia wody jest aktualizowana na
400
:Kotlin
state.addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400))
Java
state.addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400));
Polecane dla Ciebie
- Uwaga: tekst linku wyświetla się, gdy JavaScript jest wyłączony
- Migracja do przestrzeni nazw ProtoLayout
- Pierwsze kroki z kafelkami
- Inne uwagi