تحديد إصدارات المربّعات

على أجهزة Wear OS، يتم عرض البلاطات من خلال مكوّنَين رئيسيَّين لهما إصدارات مستقلة. لضمان عمل مربّعات التطبيقات بشكل صحيح على جميع الأجهزة، من المهم فهم هذه البنية الأساسية.

  • مكتبات Jetpack المتعلّقة باللوحات: هذه المكتبات (بما في ذلك Wear Tiles وWear ProtoLayout) مضمّنة في تطبيقك، ويمكنك كمطوّر التحكّم في إصداراتها. يستخدم تطبيقك هذه المكتبات لإنشاء عنصر TileBuilder.Tile (بنية البيانات التي تمثّل البلاطة) استجابةً لطلب onTileRequest() الذي يرسله النظام.
  • أداة العرض ProtoLayout: هذا المكوّن من النظام مسؤول عن عرض كائن Tile على الشاشة والتعامل مع تفاعلات المستخدم. لا يتحكّم مطوّر التطبيق في إصدار أداة العرض، وقد يختلف الإصدار من جهاز إلى آخر، حتى إذا كانت الأجهزة تتضمّن أجهزة متطابقة.

يمكن أن يختلف مظهر أو سلوك البلاطة استنادًا إلى كل من إصدارات مكتبة Jetpack Tiles في تطبيقك وإصدار أداة العرض ProtoLayout Renderer على جهاز المستخدم. على سبيل المثال، قد يتيح أحد الأجهزة تدوير الشاشة أو عرض بيانات معدّل نبضات القلب، وقد لا يتيح جهاز آخر ذلك.

يوضّح هذا المستند كيفية التأكّد من توافق تطبيقك مع الإصدارات المختلفة من مكتبة Tiles وProtoLayout Renderer، وكيفية نقل البيانات إلى إصدارات أعلى من مكتبة Jetpack.

مراعاة التوافق

لإنشاء Tile يعمل بشكل صحيح على مجموعة من الأجهزة، يجب مراعاة اختلاف ميزات الأجهزة. يمكنك إجراء ذلك من خلال استراتيجيتَين رئيسيتَين: رصد إمكانات أداة العرض في وقت التشغيل وتوفير خيارات احتياطية مدمجة.

رصد إمكانات أداة العرض

يمكنك تغيير تصميم البلاطة بشكل ديناميكي استنادًا إلى الميزات المتوفّرة على جهاز معيّن.

رصد إصدار أداة العرض

  • استخدِم طريقة getRendererSchemaVersion() الخاصة بالكائن DeviceParameters الذي تم تمريره إلى طريقتك onTileRequest(). تعرض هذه الطريقة أرقام الإصدارات الرئيسية والثانوية من ProtoLayout Renderer على الجهاز.
  • يمكنك بعد ذلك استخدام منطق شرطي في عملية تنفيذ onTileRequest() لتكييف تصميم أو سلوك Tile استنادًا إلى إصدار أداة العرض التي تم رصدها.

التعليق التوضيحي @RequiresSchemaVersion

  • يشير التعليق التوضيحي @RequiresSchemaVersion على طرق ProtoLayout إلى الحد الأدنى من إصدار مخطط العارض المطلوب لكي تعمل هذه الطريقة على النحو الموضّح (مثال).
    • على الرغم من أنّ استدعاء طريقة تتطلّب إصدارًا أحدث من برنامج العرض مقارنةً بالإصدار المتوفّر على الجهاز لن يؤدي إلى تعطُّل تطبيقك، إلا أنّه قد يؤدي إلى عدم عرض المحتوى أو تجاهل الميزة.

مثال على رصد الإصدار

val rendererVersion = requestParams.deviceConfiguration.rendererSchemaVersion

val arcElement =
    // DashedArcLine has the annotation @RequiresSchemaVersion(major = 1, minor = 500)
    // and so is supported by renderer versions 1.500 and greater
    if (
        rendererVersion.major > 1 ||
        (rendererVersion.major == 1 && rendererVersion.minor >= 500)
    ) {
        // Use DashedArcLine if the renderer supports it …
        DashedArcLine.Builder()
            .setLength(degrees(270f))
            .setThickness(8f)
            .setLinePattern(
                LayoutElementBuilders.DashedLinePattern.Builder()
                    .setGapSize(8f)
                    .setGapInterval(10f)
                    .build()
            )
            .build()
    } else {
        // … otherwise use ArcLine.
        ArcLine.Builder().setLength(degrees(270f)).setThickness(dp(8f)).build()
    }

توفير عناصر احتياطية

تتيح لك بعض المراجع تحديد قيمة احتياطية مباشرةً في أداة الإنشاء. ويكون ذلك أبسط في كثير من الأحيان من التحقّق من إصدار برنامج العرض، وهو الأسلوب المفضّل عند توفّره.

من حالات الاستخدام الشائعة توفير صورة ثابتة كبديل لرسوم متحركة بتنسيق Lottie. إذا كان الجهاز لا يتوافق مع صور Lottie المتحركة، سيتم عرض الصورة الثابتة بدلاً منها.

val lottieImage =
    ResourceBuilders.ImageResource.Builder()
        .setAndroidLottieResourceByResId(
            ResourceBuilders.AndroidLottieResourceByResId.Builder(R.raw.lottie)
                .setStartTrigger(createOnVisibleTrigger())
                .build()
        )
        // Fallback if lottie is not supported
        .setAndroidResourceByResId(
            ResourceBuilders.AndroidImageResourceByResId.Builder()
                .setResourceId(R.drawable.lottie_fallback)
                .build()
        )
        .build()

الاختبار باستخدام إصدارات مختلفة من أداة العرض

لاختبار البلاطات على إصدارات مختلفة من أداة العرض، يمكنك نشرها على إصدارات مختلفة من محاكي Wear OS. (على الأجهزة الفعلية، يتم توفير تحديثات ProtoLayout Renderer من خلال "متجر Play" أو تحديثات النظام. لا يمكن فرض تثبيت إصدار معيّن من أداة العرض.)

تستفيد ميزة "معاينة اللوحات" في Android Studio من أداة عرض مضمّنة في مكتبة Jetpack ProtoLayout التي يعتمد عليها الرمز البرمجي، لذا يمكنك اتّباع طريقة أخرى وهي الاعتماد على إصدارات مختلفة من مكتبة Jetpack عند اختبار اللوحات.

الانتقال إلى الإصدار 1.5 من Tiles / الإصدار 1.3 من ProtoLayout (Material 3 Expressive)

حدِّث مكتبات Jetpack Tile للاستفادة من أحدث التحسينات، بما في ذلك تغييرات واجهة المستخدم التي تتيح دمج "البلاطات" بسلاسة مع النظام.

يتضمّن الإصداران 1.5 من Jetpack Tiles و1.3 من Jetpack ProtoLayout العديد من التحسينات والتغييرات المهمة. ومن بينها:

  • واجهة برمجة تطبيقات تشبه Compose لوصف واجهة المستخدم
  • مكوّنات Material 3 Expressive، بما في ذلك الزر الذي يلتصق بالحافة السفلية، وإتاحة استخدام عناصر مرئية محسّنة، مثل رسومات Lottie المتحركة والمزيد من أنواع التدرّجات اللونية وأنماط خطوط الأقواس الجديدة - ملاحظة: يمكن أيضًا استخدام بعض هذه الميزات بدون نقل البيانات إلى واجهة برمجة التطبيقات الجديدة.

الاقتراحات

  • نقل جميع المربّعات في الوقت نفسه: تجنَّب الجمع بين إصدارات المربّعات المختلفة داخل تطبيقك. على الرغم من أنّ عناصر Material 3 تقع في عنصر منفصل (androidx.wear.protolayout:protolayout-material3)، ما يجعل من الممكن تقنيًا استخدام كل من مربّعات M2.5 وM3 في التطبيق نفسه، ننصحك بشدة بعدم اتّباع هذا النهج إلا إذا كان ذلك ضروريًا للغاية (على سبيل المثال، إذا كان تطبيقك يحتوي على عدد كبير من المربّعات التي لا يمكن نقلها كلها في وقت واحد).
  • اتّبِع إرشادات تجربة المستخدم في "البلاطات". نظرًا للطبيعة المنظَّمة للغاية والمستندة إلى نماذج للوحات، استخدِم التصاميم في الأمثلة الحالية كنقاط بداية لتصاميمك.
  • اختبار التطبيق على مجموعة متنوعة من أحجام الشاشات والخطوط: تتضمّن المربّعات غالبًا معلومات كثيرة، ما يجعل النص (خاصةً عند وضعه على الأزرار) عرضةً للتجاوز والقص. للحدّ من ذلك، استخدِم المكوّنات الجاهزة وتجنَّب التخصيص المكثّف. اختبِر التطبيق باستخدام ميزة معاينة البلاطات في Android Studio وعلى أجهزة حقيقية متعددة.

عملية نقل البيانات

تعديل التبعيات

أولاً، عدِّل ملف build.gradle.kts. عدِّل الإصدارات وغيِّر تبعية protolayout-material إلى protolayout-material3، كما هو موضّح:

// In build.gradle.kts

//val tilesVersion = "1.4.1"
//val protoLayoutVersion = "1.2.1"

// Use these versions for M3.
val tilesVersion = "1.5.0-rc01"
val protoLayoutVersion = "1.3.0-rc01"

 dependencies {
     // Use to implement support for wear tiles
     implementation("androidx.wear.tiles:tiles:$tilesVersion")

     // Use to utilize standard components and layouts in your tiles
     implementation("androidx.wear.protolayout:protolayout:$protoLayoutVersion")

     // Use to utilize components and layouts with Material Design in your tiles
     // implementation("androidx.wear.protolayout:protolayout-material:$protoLayoutVersion")
     implementation("androidx.wear.protolayout:protolayout-material3:$protoLayoutVersion")

     // Use to include dynamic expressions in your tiles
     implementation("androidx.wear.protolayout:protolayout-expression:$protoLayoutVersion")

     // Use to preview wear tiles in your own app
     debugImplementation("androidx.wear.tiles:tiles-renderer:$tilesVersion")

     // Use to fetch tiles from a tile provider in your tests
     testImplementation("androidx.wear.tiles:tiles-testing:$tilesVersion")
 }

لم يطرأ أي تغيير كبير على TileService

تؤثّر التغييرات الأساسية في عملية نقل البيانات هذه في مكوّنات واجهة المستخدم. نتيجةً لذلك، يجب أن يتطلّب تنفيذ TileService، بما في ذلك أي آليات لتحميل الموارد، الحد الأدنى من التعديلات أو ألا يتطلّب أي تعديلات.

الاستثناء الرئيسي هو تتبُّع نشاط المربّعات: إذا كان تطبيقك يستخدم onTileEnterEvent() أو onTileLeaveEvent()، عليك الانتقال إلى onRecentInteractionEventsAsync(). بدءًا من المستوى 36 لواجهة برمجة التطبيقات، سيتم تجميع هذه الأحداث.

تعديل رمز إنشاء التنسيق

في الإصدار 1.2 من ProtoLayout (الإصدار 2.5 من Material)، تعرض الطريقة onTileRequest() TileBuilders.Tile. احتوى هذا العنصر على عناصر مختلفة، بما في ذلك TimelineBuilders.Timeline، الذي احتوى بدوره على LayoutElement الذي يصف واجهة المستخدم للّوحة.

في الإصدار 1.3 من ProtoLayout (الإصدار M3)، لم تتغيّر بنية البيانات العامة وتدفّقها، ولكن يتم الآن إنشاء LayoutElement باستخدام أسلوب مستوحى من Compose مع تصميم يستند إلى الخانات المحدّدة (من أعلى إلى أسفل)، وهي titleSlot (اختيارية، وعادةً ما تكون مخصّصة لعنوان رئيسي أو عنوان صفحة)، وmainSlot (إلزامية، ومخصّصة للمحتوى الأساسي)، وbottomSlot (اختيارية، وغالبًا ما تكون مخصّصة لإجراءات مثل زر على الحافة أو معلومات إضافية مثل نص قصير). يتم إنشاء هذا التنسيق باستخدام الدالة primaryLayout().

تنسيق مربّع يعرض mainSlot وtitleSlot وbottomSlot
الشكل 1.: فتحات المربّع
مقارنة بين وظائف التنسيق M2.5 ووظائف التنسيق M3

M2.5

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters
) =
    PrimaryLayout.Builder(deviceConfiguration)
        .setResponsiveContentInsetEnabled(true)
        .setContent(
            Text.Builder(context, "Hello World!")
                .setTypography(Typography.TYPOGRAPHY_BODY1)
                .setColor(argb(0xFFFFFFFF.toInt()))
                .build()
        )
        .build()

التصميم 3

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
) =
    materialScope(context, deviceConfiguration) {
        primaryLayout(mainSlot = { text("Hello, World!".layoutString) })
    }

في ما يلي أبرز الاختلافات:

  1. إزالة أدوات الإنشاء تم استبدال نمط التصميم التقليدي لمكوّنات واجهة المستخدم في Material3 بصيغة أكثر تعريفية مستوحاة من Compose. (تحصل المكوّنات غير التابعة لواجهة المستخدم، مثل السلسلة/اللون/المعدِّلات، أيضًا على برامج تضمين جديدة بلغة Kotlin).
  2. وظائف التنسيق والتهيئة الموحّدة تعتمد تنسيقات M3 على دوال موحّدة للتهيئة والبنية، وهي materialScope() وprimaryLayout(). تعمل هاتان الدالتان الإلزاميتان على تهيئة بيئة M3 (اختيار المظهر ونطاق المكوّن من خلال materialScope) وتحديد التنسيق الأساسي المستند إلى الخانات (من خلال primaryLayout). ويجب استدعاء كلتا الدالتين مرة واحدة بالضبط لكل تنسيق.

التصميم

اللون

من الميزات البارزة في Material 3 Expressive ميزة "السمات الديناميكية": سيتم عرض المربّعات التي تتيح هذه الميزة (مفعّلة تلقائيًا) بالسمة التي يوفّرها النظام (يعتمد مدى توفّرها على جهاز المستخدم وإعداده).

من التغييرات الأخرى في الإصدار M3 توسيع عدد الرموز المميزة للألوان، إذ زاد من 4 إلى 29. يمكن العثور على رموز الألوان الجديدة في الفئة ColorScheme.

أسلوب الخط

على غرار M2.5، يعتمد M3 بشكل كبير على ثوابت حجم الخط المحدّدة مسبقًا، ويُنصح بعدم تحديد حجم الخط مباشرةً. تتوفّر هذه الثوابت في الفئة Typography، وتوفّر مجموعة موسّعة قليلاً من الخيارات الأكثر تعبيرًا.

للاطّلاع على التفاصيل الكاملة، يُرجى الرجوع إلى مستندات أسلوب الخط.

الشكل

يمكن أن تختلف معظم مكوّنات M3 من حيث الشكل واللون.

textButton (في mainSlot) بالشكل full:

مربّع على شكل "كامل" (زوايا أكثر استدارة)
الشكل 2.: مربّع بالشكل "كامل"

الزر textButton نفسه بالشكل small:

المربّع ذو الشكل "صغير" (زوايا أقل استدارة)
الشكل 3.: مربّع بالشكل "صغير"

المكوّنات

تتسم مكوّنات M3 بمرونة وإمكانية ضبط أكبر بكثير من مكوّنات M2.5. في حين أنّ الإصدار 2.5 من Material Design كان يتطلّب غالبًا استخدام مكوّنات منفصلة لتوفير أساليب عرض مرئية مختلفة، يستخدم الإصدار 3 بشكل متكرّر مكوّنًا "أساسيًا" عامًا ولكن يمكن ضبطه بشكل كبير مع إعدادات تلقائية جيدة.

ينطبق هذا المبدأ على التنسيق "الجذر". في الإصدار 2.5 من M، كان هذا إما PrimaryLayout أو EdgeContentLayout. في M3، بعد إنشاء MaterialScope واحد على مستوى أعلى، يتم استدعاء الدالة primaryLayout(). تعرض هذه السمة التنسيق الأساسي مباشرةً (بدون الحاجة إلى أدوات إنشاء) وتقبل LayoutElements للعديد من "الخانات"، مثل titleSlot وmainSlot وbottomSlot. يمكن ملء هذه الخانات بمكوّنات واجهة مستخدم ملموسة، مثل تلك التي تعرضها text() أو button() أو card()، أو بتصاميم، مثل Row أو Column من LayoutElementBuilders.

تمثّل المظاهر تحسينًا رئيسيًا آخر في M3. تلتزم عناصر واجهة المستخدم تلقائيًا بمواصفات تصميم M3 وتتوافق مع ميزة تغيير المظهر الديناميكي.

M2.5 التصميم 3
العناصر التفاعلية
Button أو Chip
Text
Text text()
مؤشرات التقدم
CircularProgressIndicator circularProgressIndicator() أو segmentedCircularProgressIndicator()
التصميم
PrimaryLayout أو EdgeContentLayout primaryLayout()
buttonGroup()
الصور
icon() أو avatarImage() أو backgroundImage()

مفاتيح التعديل

في M3، أصبحت Modifiers، التي تستخدمها لتزيين أحد المكوّنات أو تحسينه، أكثر تشابهًا مع Compose. يمكن أن يقلّل هذا التغيير من الرمز النموذجي من خلال إنشاء الأنواع الداخلية المناسبة تلقائيًا. (هذا التغيير مستقل عن استخدام مكوّنات واجهة المستخدم في Material 3. إذا لزم الأمر، يمكنك استخدام أدوات التعديل بنمط أداة الإنشاء من ProtoLayout 1.2 مع مكوّنات واجهة المستخدم في Material 3، والعكس صحيح).

M2.5

// A Builder-style modifier to set the opacity of an element to 0.5
fun myModifier(): ModifiersBuilders.Modifiers =
    ModifiersBuilders.Modifiers.Builder()
        .setOpacity(TypeBuilders.FloatProp.Builder(0.5F).build())
        .build()

التصميم 3

// The equivalent Compose-like modifier is much simpler
fun myModifier(): LayoutModifier = LayoutModifier.opacity(0.5F)

يمكنك إنشاء معدِّلات باستخدام أي من طريقتَي واجهة برمجة التطبيقات، ويمكنك أيضًا استخدام دالة الإضافة toProtoLayoutModifiers() لتحويل LayoutModifier إلى ModifiersBuilders.Modifier.

الدوال المساعِدة

في حين أنّ الإصدار 1.3 من ProtoLayout يتيح التعبير عن العديد من مكوّنات واجهة المستخدم باستخدام واجهة برمجة تطبيقات مستوحاة من Compose، تواصل عناصر التصميم الأساسية، مثل الصفوف والأعمدة من LayoutElementBuilders، استخدام نمط التصميم. لسدّ هذه الفجوة في الأسلوب وتعزيز التناسق مع واجهات برمجة التطبيقات الجديدة لمكوّنات M3، ننصحك باستخدام دوال مساعدة.

بدون مساعدين

primaryLayout(
    mainSlot = {
        LayoutElementBuilders.Column.Builder()
            .setWidth(expand())
            .setHeight(expand())
            .addContent(text("A".layoutString))
            .addContent(text("B".layoutString))
            .addContent(text("C".layoutString))
            .build()
    }
)

مع مساعدين

// Function literal with receiver helper function
fun column(builder: Column.Builder.() -> Unit) =
    Column.Builder().apply(builder).build()

primaryLayout(
    mainSlot = {
        column {
            setWidth(expand())
            setHeight(expand())
            addContent(text("A".layoutString))
            addContent(text("B".layoutString))
            addContent(text("C".layoutString))
        }
    }
)

الترحيل إلى الإصدار 1.2 من Tiles / الإصدار 1.0 من ProtoLayout

اعتبارًا من الإصدار 1.2، أصبحت معظم واجهات برمجة التطبيقات الخاصة بتنسيق "البلاطات" ضمن مساحة الاسم androidx.wear.protolayout. لاستخدام أحدث واجهات برمجة التطبيقات، أكمِل خطوات نقل البيانات التالية في الرمز البرمجي.

تعديل التبعيات

في ملف الإنشاء الخاص بوحدة تطبيقك، أجرِ التغييرات التالية:

Groovy

  // Remove
  implementation 'androidx.wear.tiles:tiles-material:version'

  // Include additional dependencies
  implementation "androidx.wear.protolayout:protolayout:1.3.0"
  implementation "androidx.wear.protolayout:protolayout-material:1.3.0"
  implementation "androidx.wear.protolayout:protolayout-expression:1.3.0"

  // Update
  implementation "androidx.wear.tiles:tiles:1.5.0"

Kotlin

  // Remove
  implementation("androidx.wear.tiles:tiles-material:version")

  // Include additional dependencies
  implementation("androidx.wear.protolayout:protolayout:1.3.0")
  implementation("androidx.wear.protolayout:protolayout-material:1.3.0")
  implementation("androidx.wear.protolayout:protolayout-expression:1.3.0")

  // Update
  implementation("androidx.wear.tiles:tiles:1.5.0")

تعديل مساحات الاسم

في ملفات الرموز البرمجية المستندة إلى Kotlin وJava في تطبيقك، أجرِ التعديلات التالية. بدلاً من ذلك، يمكنك تنفيذ نص برمجي لإعادة تسمية مساحة الاسم.

  1. استبدال جميع عمليات استيراد androidx.wear.tiles.material.* بـ androidx.wear.protolayout.material.* أكمِل هذه الخطوة أيضًا للمكتبة androidx.wear.tiles.material.layouts.
  2. استبدِل معظم عمليات استيراد androidx.wear.tiles.* الأخرى بـ androidx.wear.protolayout.*.

    يجب أن تبقى عمليات الاستيراد الخاصة بـ androidx.wear.tiles.EventBuilders وandroidx.wear.tiles.RequestBuilders وandroidx.wear.tiles.TileBuilders وandroidx.wear.tiles.TileService كما هي.

  3. إعادة تسمية بعض الطرق المتوقّفة نهائيًا من الفئتين TileService وTileBuilder:

    1. TileBuilders: من getTimeline() إلى getTileTimeline()، ومن setTimeline() إلى setTileTimeline()
    2. TileService: من onResourcesRequest() إلى onTileResourcesRequest()
    3. RequestBuilders.TileRequest: getDeviceParameters() إلى getDeviceConfiguration()، وsetDeviceParameters() إلى setDeviceConfiguration()، وgetState() إلى getCurrentState()، وsetState() إلى setCurrentState()