بدءًا من 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 أرقام، مع القيمة الاحتياطية --
:
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() ); }
استخدام عدد صغير من التعبيرات داخل مربع واحد
يضع Wear OS حدًّا في عدد التعبيرات التي يمكن أن يتضمّنها مربّع واحد. إذا كان أحد الأقسام يحتوي على عدد كبير جدًا من التعبيرات الديناميكية الإجمالية، يتم تجاهل القيم الديناميكية، ويعود النظام إلى القيم الثابتة التي توفّرها لأنواع الخصائص الديناميكية ذات الصلة.
يمكنك بأمان إضافة مجموعة التعبيرات التالية إلى تجانب، لأنه لا يوجد الكثير من التعبيرات الإجمالية. وبالتالي، يعمل المربّع بشكل صحيح:
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");
ومع ذلك، قد يحتوي هذا المربّع على عدد كبير جدًا من التعبيرات:
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) ); }
دمج البيانات الديناميكية في كائن حالة
يمكنك دمج آخر مجموعة من التعديلات من مصادر البيانات في حالة تنقلها إلى المربّع الخاص بك لعرض القيمة.
لاستخدام معلومات الحالة في المربّعات، اتّبِع الخطوات التالية:
أنشئ مجموعة من المفاتيح التي تمثل القيم المختلفة لحالة مربّعك. ينشئ هذا المثال مفاتيح لتناول المياه وملاحظة:
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");
أثناء تنفيذك لـ
onTileRequest()
، استدعِsetState()
وأنشئ تعيينات مبدئية من كل مفتاح إلى قيمة بيانات ديناميكية معيّنة: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() ); }
عند إنشاء التنسيق، في المكان الذي تريد عرض هذه البيانات من حالته، استخدِم كائن النوع
Dynamic*
. يمكنك أيضًا استدعاء الدالةanimate()
لعرض صورة متحركة من القيمة السابقة إلى القيمة الحالية:Kotlin
DynamicInt32.from(KEY_WATER_INTAKE).animate()
Java
DynamicInt32.from(KEY_WATER_INTAKE).animate();
ويمكنك أيضًا تعديل الحالة باستخدام قيم جديدة عند الحاجة. يمكن أن يكون هذا جزءًا من
LoadAction
الخاصة بمربّع.في هذا المثال، يتم تعديل قيمة الاستهلاك من المياه إلى
400
:Kotlin
state.addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400))
Java
state.addKeyToValueMapping(KEY_WATER_INTAKE, DynamicDataBuilders.DynamicDataValue.fromInt(400));