بدءًا من 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));
أفلام مُقترَحة لك
- ملاحظة: يظهر نص الرابط عند إيقاف JavaScript
- نقل البيانات إلى مساحات اسم ProtoLayout
- بدء استخدام الشاشات
- اعتبارات أخرى