عرض التحديثات الديناميكية في المربّعات

بدءًا من Tiles 1.2، يمكنك بث تحديثات بيانات النظام الأساسي باستخدام التعبيرات الديناميكية. يمكنك بعد ذلك ربط هذه التحديثات بالرسوم المتحركة في المربعات. ويتلقى تطبيقك تحديثات لهذه القيمة كل ثانية.

باستخدام التعبيرات الديناميكية، لا تحتاج إلى تحديث المربّع بالكامل عند تغيير محتواه. لتقديم تجربة أكثر جاذبية في المربّعات، أضِف تأثيرات حركية إلى تلك العناصر الديناميكية.

ربط التعبيرات الديناميكية بمصادر البيانات

تحتوي مساحات الاسم androidx.wear.protolayout وandroidx.wear.protolayout.material على العديد من الفئات التي تقبل حقولها التعبيرات الديناميكية. تشمل بعض الأمثلة ما يلي:

لاستخدام تعبير ديناميكي كقيمة محتملة لعنصر في مربّعك، استخدِم نوع السمة الديناميكية *Prop المقابل للعنصر ومرِّر مصدر البيانات إلى طريقة setDynamicValue() الخاصة بفئة إنشاء الموقع الديناميكي.

تتوافق المربّعات مع أنواع المواقع الديناميكية التالية:

عند استخدام تعبير ديناميكي يؤثر في الأبعاد المادية، أي قيمة في مربع باستثناء اللون، يجب أيضًا تحديد مجموعة من القيود ذات الصلة، مثل تنسيق السلسلة. تسمح هذه القيود لعارض النظام بتحديد الحد الأقصى للمساحة التي يمكن أن تشغلها القيمة داخل المربع الخاص بك. عادةً ما تحدّد هذه القيود على مستوى العنصر، وليس على مستوى التعبير الديناميكي، من خلال استدعاء طريقة تبدأ بـ 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)
    );
}

دمج البيانات الديناميكية في كائن حالة

يمكنك دمج آخر مجموعة من التعديلات من مصادر البيانات في حالة تنقلها إلى المربّع الخاص بك لعرض القيمة.

لاستخدام معلومات الحالة في المربّعات، اتّبِع الخطوات التالية:

  1. أنشئ مجموعة من المفاتيح التي تمثل القيم المختلفة لحالة مربّعك. ينشئ هذا المثال مفاتيح لتناول المياه وملاحظة:

    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");
    
  2. أثناء تنفيذك لـ 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()
        );
    }
    
  3. عند إنشاء التنسيق، في المكان الذي تريد عرض هذه البيانات من حالته، استخدِم كائن النوع Dynamic*. يمكنك أيضًا استدعاء الدالة animate() لعرض صورة متحركة من القيمة السابقة إلى القيمة الحالية:

    Kotlin

    DynamicInt32.from(KEY_WATER_INTAKE).animate()
    

    Java

    DynamicInt32.from(KEY_WATER_INTAKE).animate();
    
  4. ويمكنك أيضًا تعديل الحالة باستخدام قيم جديدة عند الحاجة. يمكن أن يكون هذا جزءًا من LoadAction الخاصة بمربّع.

    في هذا المثال، يتم تعديل قيمة الاستهلاك من المياه إلى 400:

    Kotlin

    state.addKeyToValueMapping(KEY_WATER_INTAKE,
            DynamicDataBuilders.DynamicDataValue.fromInt(400))
    

    Java

    state.addKeyToValueMapping(KEY_WATER_INTAKE,
            DynamicDataBuilders.DynamicDataValue.fromInt(400));