بدء استخدام الشاشات

لبدء توفير مربّعات معلومات من تطبيقك، أدرِج التبعيات التالية فيملفbuild.gradle الخاص بتطبيقك.

رائع

dependencies {
    // Use to implement support for wear tiles
    implementation "androidx.wear.tiles:tiles:1.5.0-alpha04"

    // Use to utilize standard components and layouts in your tiles
    implementation "androidx.wear.protolayout:protolayout:1.3.0-alpha04"

    // Use to utilize components and layouts with Material Design in your tiles
    implementation "androidx.wear.protolayout:protolayout-material:1.3.0-alpha04"

    // Use to include dynamic expressions in your tiles
    implementation "androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04"

    // Use to preview wear tiles in your own app
    debugImplementation "androidx.wear.tiles:tiles-renderer:1.5.0-alpha04"

    // Use to fetch tiles from a tile provider in your tests
    testImplementation "androidx.wear.tiles:tiles-testing:1.5.0-alpha04"
}

Kotlin

dependencies {
    // Use to implement support for wear tiles
    implementation("androidx.wear.tiles:tiles:1.5.0-alpha04")

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

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

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

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

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

إنشاء مربّع

لتوفير مربّع معلومات من تطبيقك، أنشئ فئة تمثّل superclass TileService ونفِّذ الطرق، كما هو موضّح في نموذج الرمز البرمجي التالي:

class MyTileService : TileService() {

    override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
        Futures.immediateFuture(
            Tile.Builder()
                .setResourcesVersion(RESOURCES_VERSION)
                .setTileTimeline(
                    Timeline.fromLayoutElement(
                        Text.Builder(this, "Hello World!")
                            .setTypography(Typography.TYPOGRAPHY_BODY1)
                            .setColor(argb(0xFFFFFFFF.toInt()))
                            .build()
                    )
                )
                .build()
        )

    override fun onTileResourcesRequest(requestParams: ResourcesRequest) =
        Futures.immediateFuture(
            Resources.Builder()
                .setVersion(RESOURCES_VERSION)
                .build()
        )
}

بعد ذلك، أضِف خدمة داخل علامة <application> في ملف AndroidManifest.xml.

<service
    android:name=".snippets.tile.MyTileService"
    android:label="@string/tile_label"
    android:description="@string/tile_description"
    android:icon="@mipmap/ic_launcher"
    android:exported="true"
    android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
    <intent-filter>
        <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
    </intent-filter>

    <meta-data android:name="androidx.wear.tiles.PREVIEW"
        android:resource="@drawable/tile_preview" />
</service>

يسجِّل فلتر الإذن والهدف هذه الخدمة كمقدّم مربّعات معلومات.

يظهر للمستخدم رمز المربّع وتسميته ووصفه ومصدر المعاينة عند ضبط مربّعات الشاشة على هاتفه أو ساعته.

نظرة عامة على دورة حياة خدمة مربّعات المعلومات

بعد إنشاء TileService وتعريفه في بيان تطبيقك، يمكنك الاستجابة لتغييرات حالة خدمة مربّعات المعلومات.

TileService هي خدمة ربط. يتم ربط TileService نتيجةً لطلب تطبيقك أو إذا كان النظام بحاجة إلى التواصل معه. تحتوي دورة حياة الخدمة المرتبطة النموذجية على طُرق الاستدعاء الأربعة التالية: onCreate() وonBind() وonUnbind() و onDestroy(). يستدعي النظام هذه الطرق في كل مرة تدخل فيها الخدمة في مرحلة جديدة من دورة الحياة.

بالإضافة إلى وظائف الاستدعاء التي تتحكّم في دورة حياة الخدمة المرتبطة، يمكنك تنفيذ طرق أخرى خاصة بدورة حياة TileService. يجب أن تنفِّذ جميع خدمات الشاشة المفردة onTileRequest() وonTileResourcesRequest() لتلقّي طلبات التحديثات من النظام والردّ عليها.

  • onTileAddEvent(): لا يستدعي النظام هذه الطريقة إلا عندما يُضيف المستخدم مربّعك للمرة الأولى، وإذا أزال المستخدم مربّعك وأعاد إضافته. هذا هو أفضل وقت لإجراء أي عملية إعداد لمرة واحدة.

    لا يتمّ استدعاء onTileAddEvent() إلا عند إعادة ضبط مجموعة مربّعات المعلومات، وليس عند إنشاء مربّع معلومات من قِبل النظام. على سبيل المثال، عند إعادة تشغيل الجهاز أو تشغيله، لا يتم استدعاء onTileAddEvent() للمربّعات التي سبق أن تمت إضافتها. يمكنك استخدام getActiveTilesAsync() بدلاً من ذلك للحصول على لقطة شاشة للمربّعات التي تملكها والتي تكون نشطة.

  • onTileRemoveEvent(): لا يستدعي النظام هذه الطريقة إلا إذا أزال المستخدم مربّعك.

  • onTileEnterEvent(): يستدعي النظام هذه الطريقة عندما يظهر مربّع يقدّمه هذا الموفِّر على الشاشة.

  • onTileLeaveEvent(): يستدعي النظام هذه الطريقة عندما يختفي مربّع يقدّمه هذا الموفِّر من الشاشة.

  • onTileRequest(): يستدعي النظام هذه الطريقة عندما يطلب مخططًا زمنيًا جديدًا من هذا الموفِّر.

  • onTileResourcesRequest(): يستدعي النظام هذه الطريقة عندما يطلب النظام حزمة موارد من هذا الموفِّر. ويمكن أن يحدث ذلك في المرة الأولى التي يتم فيها تحميل مربّع أو عند تغيُّر إصدار المورد.

طلب عرض المربّعات النشطة

البطاقات النشطة هي البطاقات التي تمت إضافتها للعرض على الساعة. استخدِم الأسلوب الثابت getActiveTilesAsync() في TileServiceلطلب البحث عن المربّعات التي تخصّ تطبيقك وتكون نشطة.

إنشاء واجهة مستخدم للقوائم

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

عناصر التنسيق الأساسية

تتوفّر العناصر المرئية التالية من مكتبة protolayout، بالإضافة إلى مكونات Material Design:

  • Text: لعرض سلسلة من النصوص مع إمكانية لفّها اختياريًا
  • Image: لعرض صورة.
  • Spacer: يضيف هذا العنصر مساحة بين العناصر أو يمكن أن يعمل كفاصل عند ضبط لون الخلفية.

مكوّنات التصميم المادّي

بالإضافة إلى العناصر الأساسية، توفّر مكتبة protolayout-material مكونات تضمن تصميم مربّعات معلومات يتوافق مع اقتراحات واجهة مستخدم Material Design.

  • Button: عنصر دائري قابل للنقر عليه مصمّم ليحتوي على رمز.
  • Chip: عنصر قابل للنقر عليه berbentuk مثلث مصمّم ليحتوي على ما يصل إلى سطرَين من النص ورمز اختياري.

  • CompactChip: عنصر على شكل ملعب قابل للنقر مصمّم ليحتوي على سطر من النص.

  • TitleChip: عنصر على شكل ملعب قابل للنقر يشبه Chip ولكن بارتفاع أكبر لاستيعاب نص العنوان

  • CircularProgressIndicator: مؤشر تقدم دائري يمكن وضعه داخل EdgeContentLayout لعرض مستوى التقدّم حول حواف الشاشة

حاويات التنسيق

تتوفّر الحاويات التالية، بالإضافة إلى تنسيقات Material:

  • Row: لعرض العناصر الفرعية بشكل أفقي، واحدة تلو الأخرى
  • Column: يعرض العناصر الفرعية عموديًا، تلو الأخرى.
  • Box: تتراكب العناصر الفرعية فوق بعضها.
  • Arc: لعرض العناصر الفرعية في دائرة
  • Spannable: يطبّق FontStyles محددًا على أقسام من النص مع تداخل النص والصور. لمزيد من المعلومات، يُرجى الاطّلاع على العناصر التي يمكن تمديدها.

يمكن أن تحتوي كل حاوية على عنصر ثانوي واحد أو أكثر، ويمكن أن تكون هذه العناصر بدورها حاويات. على سبيل المثال، يمكن أن يحتوي Column على عناصر Row متعددة كعناصر تابعة، ما يؤدي إلى إنشاء تنسيق شبيه بالشبكة.

على سبيل المثال، يمكن أن يظهر مربّع مع تنسيق حاوية وعنصرَي تنسيق فرعيَين بالشكل التالي:

Kotlin

private fun myLayout(): LayoutElement =
    Row.Builder()
        .setWidth(wrap())
        .setHeight(expand())
        .setVerticalAlignment(VALIGN_BOTTOM)
        .addContent(Text.Builder()
            .setText("Hello world")
            .build()
        )
        .addContent(Image.Builder()
            .setResourceId("image_id")
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .build()
        ).build()

Java

private LayoutElement myLayout() {
    return new Row.Builder()
        .setWidth(wrap())
        .setHeight(expand())
        .setVerticalAlignment(VALIGN_BOTTOM)
        .addContent(new Text.Builder()
            .setText("Hello world")
            .build()
        )
        .addContent(new Image.Builder()
            .setResourceId("image_id")
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .build()
        ).build();
}

تنسيقات المواد

بالإضافة إلى التنسيقات الأساسية، تقدّم مكتبة protolayout-material بعض التنسيقات التي تعكس رأيًا معيّنًا ومصمّمة لعرض العناصر في "مَواضع" معيّنة.

  • PrimaryLayout: يضع هذا الرمز إجراءً أساسيًا واحدًا CompactChip في أسفل الصفحة مع وضع المحتوى في منتصف الصفحة فوقه.

  • MultiSlotLayout: يضع هذا الخيار التصنيفات الأساسية والثانوية مع محتوى اختياري بينهما ويضعCompactChip اختياريًا في أسفل الصفحة.

  • MultiButtonLayout: يحدد موضع مجموعة من الأزرار التي يتم ترتيبها وفقًا لإرشادات Material Design.

  • EdgeContentLayout: يُعدّل موضع المحتوى حول حافة الشاشة، مثل CircularProgressIndicator. عند استخدام هذا التنسيق، يتم تلقائيًا تطبيق الهوامش والوسائط المناسبة على المحتوى المضمّن فيه.

أقواس

يمكن استخدام العناصر الثانوية التالية لحاوية Arc:

  • ArcLine: يعرض خطًا منحنيًا حول القوس.
  • ArcText: يعرض نصًا منحنيًا في Arc.
  • ArcAdapter: يعرض عنصر تنسيق أساسي في القوس، ويتم رسمه بشكل موازٍ للقوس.

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

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

يمكن تطبيق عوامل تعديل اختيارية على كل عنصر تنسيق متاح. استخدِم مفاتيح التعديل هذه للأغراض التالية:

  • تغيير المظهر المرئي للتنسيق على سبيل المثال، أضِف خلفية أو حدودًا أو مساحة تملأ الفراغ بين عناصر التنسيق.
  • أضِف بيانات وصفية عن التنسيق. على سبيل المثال، أضِف مُعدِّلًا للدلالات إلى عنصر التنسيق لاستخدامه مع تطبيقات قراءة الشاشة.
  • إضافة وظائف على سبيل المثال، أضِف مُعدِّلًا قابلاً للنقر إلى عنصر التنسيق لجعل مربّع الرموز تفاعليًا. لمزيد من المعلومات، يُرجى الاطّلاع على التفاعل مع المربّعات.

على سبيل المثال، يمكننا تخصيص المظهر التلقائي والبيانات الوصفية لملف Image، كما هو موضّح في نموذج الرمز البرمجي التالي:

Kotlin

private fun myImage(): LayoutElement =
    Image.Builder()
        .setWidth(dp(24f))
        .setHeight(dp(24f))
        .setResourceId("image_id")
        .setModifiers(Modifiers.Builder()
            .setBackground(Background.Builder().setColor(argb(0xFFFF0000)).build())
            .setPadding(Padding.Builder().setStart(dp(12f)).build())
            .setSemantics(Semantics.builder()
                .setContentDescription("Image description")
                .build()
            ).build()
        ).build()

Java

private LayoutElement myImage() {
   return new Image.Builder()
           .setWidth(dp(24f))
           .setHeight(dp(24f))
           .setResourceId("image_id")
           .setModifiers(new Modifiers.Builder()
                   .setBackground(new Background.Builder().setColor(argb(0xFFFF0000)).build())
                   .setPadding(new Padding.Builder().setStart(dp(12f)).build())
                   .setSemantics(new Semantics.Builder()
                           .setContentDescription("Image description")
                           .build()
                   ).build()
           ).build();
}

العناصر التي يمكن توسيع نطاقها

Spannable هو نوع خاص من الحاويات يعرض العناصر بشكل مشابه للنص. يكون هذا مفيدًا عندما تريد تطبيق نمط مختلف على سلسلة فرعية واحدة فقط في كتلة نص أكبر، وهو أمر غير ممكن باستخدام العنصر Text.

حاوية Spannable مليئة ب Span أطفال. ولا يُسمح بعناصر فرعية أخرى أو نُسخ Spannable متداخلة.

هناك نوعان من Span الأطفال:

  • SpanText: يعرض النص بنمط معيّن.
  • SpanImage: لعرض صورة مضمّنة في النص

على سبيل المثال، يمكنك استخدام مائل على كلمة "world" في مربّع "مرحبًا بك" وإدراج صورة بين الكلمات، كما هو موضّح في نموذج التعليمات البرمجية التالي:

Kotlin

private fun mySpannable(): LayoutElement =
    Spannable.Builder()
        .addSpan(SpanText.Builder()
            .setText("Hello ")
            .build()
        )
        .addSpan(SpanImage.Builder()
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .setResourceId("image_id")
            .build()
        )
        .addSpan(SpanText.Builder()
            .setText("world")
            .setFontStyle(FontStyle.Builder()
                .setItalic(true)
                .build())
            .build()
        ).build()

Java

private LayoutElement mySpannable() {
   return new Spannable.Builder()
        .addSpan(new SpanText.Builder()
            .setText("Hello ")
            .build()
        )
        .addSpan(new SpanImage.Builder()
            .setWidth(dp(24f))
            .setHeight(dp(24f))
            .setResourceId("image_id")
            .build()
        )
        .addSpan(new SpanText.Builder()
            .setText("world")
            .setFontStyle(newFontStyle.Builder()
                .setItalic(true)
                .build())
            .build()
        ).build();
}

العمل مع المراجع

لا يمكن للقوائم الوصول إلى أي من موارد تطبيقك. وهذا يعني أنّه لا يمكنك تمرير معرّف صورة Android إلى عنصر تخطيط Image والتوقع أن يتم حلّ المشكلة. بدلاً من ذلك، يمكنك إلغاء الطريقة onTileResourcesRequest() وتقديم أي موارد يدويًا.

هناك طريقتان لتقديم الصور ضمن onTileResourcesRequest() الطريقة:

Kotlin

override fun onTileResourcesRequest(
    requestParams: ResourcesRequest
) = Futures.immediateFuture(
Resources.Builder()
    .setVersion("1")
    .addIdToImageMapping("image_from_resource", ImageResource.Builder()
        .setAndroidResourceByResId(AndroidImageResourceByResId.Builder()
            .setResourceId(R.drawable.image_id)
            .build()
        ).build()
    )
    .addIdToImageMapping("image_inline", ImageResource.Builder()
        .setInlineResource(InlineImageResource.Builder()
            .setData(imageAsByteArray)
            .setWidthPx(48)
            .setHeightPx(48)
            .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565)
            .build()
        ).build()
    ).build()
)

Java

@Override
protected ListenableFuture<Resources> onTileResourcesRequest(
       @NonNull ResourcesRequest requestParams
) {
return Futures.immediateFuture(
    new Resources.Builder()
        .setVersion("1")
        .addIdToImageMapping("image_from_resource", new ImageResource.Builder()
            .setAndroidResourceByResId(new AndroidImageResourceByResId.Builder()
                .setResourceId(R.drawable.image_id)
                .build()
            ).build()
        )
        .addIdToImageMapping("image_inline", new ImageResource.Builder()
            .setInlineResource(new InlineImageResource.Builder()
                .setData(imageAsByteArray)
                .setWidthPx(48)
                .setHeightPx(48)
                .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565)
                .build()
            ).build()
        ).build()
);
}