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

بدءًا من 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));