إنشاء تطبيق مصغّر باستخدام ميزة "نظرة سريعة"

توضّح الأقسام التالية كيفية إنشاء أداة أساسية للتطبيق باستخدام Glance.

الإعلان عن AppWidget في ملف البيان

بعد إكمال خطوات الإعداد، عليك الإعلان عن AppWidget والبيانات الوصفية الخاصة به في تطبيقك.

  1. عليك توسيع أداة استقبال AppWidget من GlanceAppWidgetReceiver:

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
        override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget")
    }

  2. عليك تسجيل موفِّر أداة التطبيق في ملف AndroidManifest.xml وملف البيانات الوصفية المرتبطَين:

        <receiver android:name=".glance.MyReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/my_app_widget_info" />
    </receiver>
    

إضافة البيانات الوصفية AppWidgetProviderInfo

بعد ذلك، اتّبِع دليل إنشاء أداة لإنشاء معلومات أداة التطبيق وتحديدها في الملف @xml/my_app_widget_info.

الفرق الوحيد في Glance هو أنّه لا يتوفّر ملف XML لـ initialLayout، ولكن عليك تحديد ملف. يمكنك استخدام تنسيق التحميل المحدّد مسبقًا والمقدَّم في المكتبة:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>

الإعلان عن AppWidgetProviderInfo XML

يحدّد العنصر AppWidgetProviderInfo الخصائص الأساسية لأداتك. عليك تحديد AppWidgetProviderInfo في ملف مصدر البيانات الوصفية بتنسيق XML (res/xml/my_app_widget_info.xml) داخل عنصر <appwidget-provider>:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:targetCellWidth="1"
    android:targetCellHeight="1"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="120dp"
    android:updatePeriodMillis="86400000"
    android:description="@string/example_appwidget_description"
    android:previewLayout="@layout/example_appwidget_preview"
    android:initialLayout="@layout/glance_default_loading_layout"
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

سمات تغيير حجم الأداة

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

تتيح لك سمات تغيير حجم الأداة تحديد حجم تلقائي لأداتك وتوفير حدود دنيا وعليا لحجم الأداة. في هذا السياق، يكون الحجم التلقائي للأداة هو الحجم الذي تتخذه الأداة عند إضافتها لأول مرة إلى الشاشة الرئيسية.

يصف الجدول التالي سمات <appwidget-provider> المتعلّقة بتغيير حجم الأداة:

السمات والوصف
targetCellWidth و targetCellHeight (الإصدار Android 12)، و minWidth وminHeight
  • بدءًا من الإصدار Android 12، تحدّد السمتان targetCellWidth وtargetCellHeight الحجم التلقائي للأداة من حيث خلايا الشبكة. يتم تجاهل هاتَين السمتَين في الإصدار Android 11 والإصدارات الأقدم، ويمكن تجاهلهما إذا كانت الشاشة الرئيسية لا تتيح تنسيقًا مستندًا إلى الشبكة.
  • تحدّد السمتان minWidth و minHeight الحجم التلقائي للأداة بوحدة dp. إذا لم تتطابق قيمتا الحد الأدنى لعرض الأداة أو ارتفاعها مع أبعاد الخلايا، يتم تقريب القيم إلى أقرب حجم خلية.
ننصحك بتحديد كلتا مجموعتَي السمات، أي targetCellWidth و targetCellHeight، وminWidth و minHeight، حتى يتمكّن تطبيقك من الرجوع إلى استخدام minWidth وminHeight إذا كان جهاز المستخدِم لا يتيح targetCellWidth و targetCellHeight. إذا كانت السمتان targetCellWidth وtargetCellHeight متاحتَين، تكون لهما الأولوية على السمتَين minWidth وminHeight.
minResizeWidth و minResizeHeight تحدّد هاتان السمتان الحد الأدنى المطلق لحجم الأداة. تحدّد هاتان القيمتان الـ حجم الذي تصبح الأداة غير قابلة للقراءة أو غير قابلة للاستخدام تحته. يتيح استخدام هاتَين السمتَين للمستخدِم تغيير حجم الأداة إلى حجم أصغر من الحجم التلقائي للأداة. يتم تجاهل السمة minResizeWidth إذا كانت أكبر من minWidth أو إذا لم يكن تغيير الحجم أفقيًا مفعّلاً. اطّلِع على resizeMode. وبالمثل، يتم تجاهل السمة minResizeHeight إذا كانت أكبر من minHeight أو إذا لم يكن تغيير الحجم عموديًا مفعّلاً.
maxResizeWidth و maxResizeHeight تحدّد هاتان السمتان الحد الأقصى المقترَح لحجم الأداة. إذا لم تكن القيم مضاعفات لأبعاد خلية الشبكة، يتم تقريبها إلى أقرب حجم خلية. يتم تجاهل السمة maxResizeWidth إذا كانت أصغر من minWidth أو إذا لم يكن تغيير الحجم أفقيًا مفعّلاً. اطّلِع على resizeMode. وبالمثل، يتم تجاهل السمة maxResizeHeight إذا كانت أصغر من minHeight أو إذا لم يكن تغيير الحجم عموديًا مفعّلاً. تم طرح هاتَين السمتَين في الإصدار Android 12.
resizeMode تحدّد هذه السمة القواعد التي يمكن بموجبها تغيير حجم الأداة. يمكنك استخدام هذه السمة لجعل أدوات الشاشة الرئيسية قابلة لتغيير الحجم أفقيًا أو عموديًا أو على كلا المحورَين. ينقر المستخدِمون مع الاستمرار على أداة لعرض مقابض تغيير الحجم، ثم يسحبون المقابض الأفقية أو العمودية لتغيير حجمها على شبكة التنسيق. تشمل قيم السمة resizeMode كلاً من horizontal وvertical وnone. للإعلان عن أداة قابلة لتغيير الحجم أفقيًا وعموديًا، استخدِم horizontal|vertical.

مثال

لتوضيح كيفية تأثير السمات في الجدول السابق على تغيير حجم الأداة، لنفترض المواصفات التالية:

  • عرض خلية الشبكة 30 dp وارتفاعها 50 dp.
  • تم تقديم مواصفات السمة التالية:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="80dp"
    android:minHeight="80dp"
    android:targetCellWidth="2"
    android:targetCellHeight="2"
    android:minResizeWidth="40dp"
    android:minResizeHeight="40dp"
    android:maxResizeWidth="120dp"
    android:maxResizeHeight="120dp"
    android:resizeMode="horizontal|vertical" />

بدءًا من الإصدار Android 12:

استخدِم السمتَين targetCellWidth وtargetCellHeight كحجم تلقائي للأداة.

حجم الأداة هو ‎2×2 تلقائيًا. يمكن تغيير حجم الأداة إلى ‎2×1 أو ‎4×3.

الإصدار Android 11 والإصدارات الأقدم:

استخدِم السمتَين minWidth وminHeight لحساب الحجم التلقائي للأداة.

العرض التلقائي = Math.ceil(80 / 30) = 3

الارتفاع التلقائي = Math.ceil(80 / 50) = 2

حجم الأداة هو ‎3×2 تلقائيًا. يمكن تغيير حجم الأداة إلى ‎2×1 أو ملء الشاشة.

سمات الأداة الإضافية

يصف الجدول التالي سمات <appwidget-provider> المتعلّقة بالخصائص الأخرى غير تغيير حجم الأداة.

السمات والوصف
updatePeriodMillis تحدّد هذه السمة عدد المرات التي يطلب فيها إطار عمل الأداة تحديثًا من GlanceAppWidgetReceiver من خلال استدعاء طريقة معاودة الاتصال onUpdate(). ننصحك بإجراء التحديث بأقل قدر ممكن من التكرار، أي مرة واحدة في الساعة على الأكثر، للحفاظ على البطارية. لمزيد من التفاصيل، اطّلِع على قسم وقت تحديث الأدوات في إدارة حالة Glance.
initialLayout تشير هذه السمة إلى مصدر التنسيق الذي يحدّد تنسيق التحميل للأداة قبل عرض تركيبات واجهة مستخدم Glance. يمكنك استخدام تنسيق التحميل المحدّد مسبقًا والمقدَّم في المكتبة: @layout/glance_default_loading_layout.
configure تحدّد هذه السمة نشاط الإعداد الذي يتم تشغيله عندما يضيف المستخدِم الأداة. اطّلِع على دليل السماح للمستخدِمين بإعداد أدوات التطبيقات.
description تحدّد هذه السمة الوصف الذي يعرضه منتقي الأدوات لأداتك. تم طرح هذه السمة في الإصدار Android 12.
previewLayout (الإصدار Android 12) وpreviewImage (الإصدار Android 11 والإصدارات الأقدم)
  • بدءًا من الإصدار Android 12، تحدّد السمة previewLayout معاينة قابلة لتغيير الحجم، والتي تقدّمها كمجموعة تنسيق XML تم ضبطها على الحجم التلقائي للأداة. من المفترَض أن تشير هذه السمة إلى عملية ربط XML ثابتة تطابق تنسيق التصميم.
  • في الإصدار Android 11 أو الإصدارات الأقدم، تحدّد السمة previewImage لقطة شاشة لصورة ثابتة قابلة للرسم لما تبدو عليه الأداة، وتظهر في منتقي الأدوات.
ننصحك بتحديد كلتا السمتَين حتى يتمكن تطبيقك من الرجوع إلى المنصات القديمة بسلاسة. بالنسبة إلى المنصات الأحدث (الإصدار Android 15 والإصدارات الأحدث)، يمكنك تحديد معاينات تم إنشاؤها مباشرةً في Kotlin باستخدام `GlanceAppWidget.providePreview`. اطّلِع على دليل المعاينات التي تم إنشاؤها.
autoAdvanceViewId تحدّد هذه السمة رقم تعريف العرض للعرض الفرعي للأداة الذي يتم تقدّمه تلقائيًا من قِبل مضيف الأداة.
widgetCategory تحدّد هذه السمة ما إذا كان يمكن عرض أداتك على الشاشة الرئيسية (home_screen) أو شاشة القفل (keyguard) أو كلتيهما. بالنسبة إلى الإصدار Android 5.0 والإصدارات الأحدث، تكون home_screen فقط هي القيمة الصالحة.
widgetFeatures تحدّد هذه السمة الميزات التي تتيحها الأداة. على سبيل المثال، إذا كان إعداد أداتك اختياريًا، حدّد كلاً من configuration_optional وreconfigurable.

تحديد GlanceAppWidget

  1. أنشِئ فئة جديدة توسّع من GlanceAppWidget وتتجاوز الطريقة provideGlance. هذه هي الطريقة التي يمكنك من خلالها تحميل البيانات اللازمة لعرض أداتك:

    class MyAppWidget : GlanceAppWidget() {
    
        override suspend fun provideGlance(context: Context, id: GlanceId) {
    
            // In this method, load data needed to render the AppWidget.
            // Use `withContext` to switch to another thread for long running
            // operations.
    
            provideContent {
                // create your AppWidget here
                Text("Hello World")
            }
        }
    }

  2. أنشِئ مثيلاً لها في glanceAppWidget على GlanceAppWidgetReceiver:

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
    
        // Let MyAppWidgetReceiver know which GlanceAppWidget to use
        override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
    }

لقد أعددت الآن AppWidget باستخدام Glance.

استخدِم فئة GlanceAppWidgetReceiver لمعالجة عمليات بث الأداة

تنسّق GlanceAppWidgetReceiver أداة الإحداثيات عمليات بث وتعديلات حالة المنصة من خلال توسيع AppWidgetProvider الأساسي. تتلقّى هذه الفئة أحداث المنصة عند تعديل أداتك أو حذفها أو تفعيلها أو إيقافها، وتحوّلها إلى طلبات دورة حياة Compose.

التعريف بتطبيق مصغّر في ملف البيان

أعلِن عن الفئة الفرعية GlanceAppWidgetReceiver كمستقبِل بث في ملف AndroidManifest.xml:

<receiver android:name="MyReceiver"
          android:exported="false">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/my_app_widget_info" />
</receiver>

يتطلّب العنصر <receiver> السمة android:name التي تحدّد فئة أداة الاستقبال. يجب أن تقبل أداة الاستقبال إجراء بث ACTION_APPWIDGET_UPDATE داخل <intent-filter>.

يجب أن تحدّد السمة <meta-data> اسمها على أنّه android.appwidget.provider، ويجب أن تشير السمة android:resource إلى مصدر البيانات الوصفية بتنسيق XML لـ AppWidgetProviderInfo (@xml/my_app_widget_info).

تنفيذ فئة GlanceAppWidgetReceiver

في Glance، عليك توسيع GlanceAppWidgetReceiver بدلاً من AppWidgetProvider مباشرةً. نفِّذها من خلال ربط أداة الاستقبال بمثيل GlanceAppWidget. تعمل معاودات الاتصال الأساسية المتاحة في GlanceAppWidgetReceiver على النحو التالي:

  • onUpdate(): يتم تجاوزها تلقائيًا من قِبل Glance لتنفيذ تعديلات التركيب. إذا تجاوزت onUpdate يدويًا، عليك استدعاء super.onUpdate للسماح لـ Glance بتشغيل سلاسل تعليمات التركيب بنجاح.
  • onAppWidgetOptionsChanged(): يتم استدعاؤها عند وضع الأداة لأول مرة أو تغيير حجمها. يقرأ Glance عناصر حزمة الخيارات تحت الغطاء، لذا يتم تعديل تنسيقك بسلاسة استنادًا إلى الأبعاد في وقت التشغيل.
  • onDeleted(Context, IntArray): يتم استدعاؤها كلما حذف المستخدِم مثيلاً معيّنًا للأداة.
  • onEnabled(Context): يتم تشغيلها عند إنشاء أول مثيل لأداتك بنجاح. هذه الطريقة ممتازة لتشغيل عمليات النقل العامة.
  • onDisabled(Context): يتم استدعاؤها عند إزالة آخر مثيل نشط للموفِّر.
  • onReceive(Context, Intent): تعترض هذه الطريقة كل عمليات بث المنصة قبل طرق معاودة الاتصال المحدّدة. عليك التأكّد من أنّ أي منطق مخصّص لأداة الاستقبال تكتبه يستدعي super.onReceive(context, intent) ويجب ألا تستدعي goAsync بنفسك لأنّ Glance توجّه العمل تلقائيًا بشكل غير متزامن.

تلقّي أغراض بث الأداة

تحت الغطاء، تعمل GlanceAppWidgetReceiver على فلترة أغراض بث الأداة الأساسية التالية للمنصة ومعالجتها:

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

يوضّح المقتطف التالي كيفية إنشاء واجهة المستخدم:

/* Import Glance Composables
 In the event there is a name clash with the Compose classes of the same name,
 you may rename the imports per https://kotlinlang.org/docs/packages.html#imports
 using the `as` keyword.

import androidx.glance.Button
import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.text.Text
*/
class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // Load data needed to render the AppWidget.
        // Use `withContext` to switch to another thread for long running
        // operations.

        provideContent {
            // create your AppWidget here
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        Column(
            modifier = GlanceModifier.fillMaxSize(),
            verticalAlignment = Alignment.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button(
                    text = "Home",
                    onClick = actionStartActivity<MyActivity>()
                )
                Button(
                    text = "Work",
                    onClick = actionStartActivity<MyActivity>()
                )
            }
        }
    }
}

يفعل نموذج الرمز البرمجي السابق ما يلي:

  • في Column على المستوى الأعلى، يتم وضع العناصر عموديًا واحدًا تلو الآخر.
  • توسّع Column حجمها ليطابق المساحة المتاحة (من خلال الـ GlanceModifier وتضبط محتواها على أعلى (verticalAlignment) وتوسّطه أفقيًا (horizontalAlignment).
  • يتم تحديد محتوى Column باستخدام تعبير لامدا. الترتيب مهم.
    • العنصر الأول في Column هو مكوّن Text مع مساحة ترك مسافة داخلية تبلغ 12.dp.
    • العنصر الثاني هو Row، حيث يتم وضع العناصر أفقيًا واحدًا تلو الآخر، مع Buttons مُوسّطَين أفقيًا (horizontalAlignment). يعتمد العرض النهائي على المساحة المتاحة. تعرض الصورة التالية مثالاً على الشكل الذي قد تبدو عليه:
destination_widget
الشكل 1. مثال على واجهة مستخدم

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

تنفيذ الزوايا المستديرة

يطرح الإصدار Android 12 معلّمات النظام لتخصيص أنصاف أقطار زوايا أدوات التطبيقات ديناميكيًا:

  • system_app_widget_background_radius: تحدّد هذه السمة نصف قطر زاوية حاوية خلفية الأداة (لا يزيد عن 28 dp).
  • نصف القطر الداخلي: لمنع اقتصاص المحتوى، احسب نصف قطر متناسبًا لمحتواك الداخلي استنادًا إلى المخطط التفصيلي لخلفية النظام: systemRadiusValue - widgetPadding

في Glance، يمكنك تطبيق خصائص تغيير حجم نصف قطر الزاوية ديناميكيًا في التركيب باستخدام GlanceModifier.cornerRadius(android.R.dimen.system_app_widget_background_radius).

لضمان التوافق مع الإصدارات السابقة على الأجهزة التي تعمل بالإصدار Android 11 (المستوى 30 لواجهة برمجة التطبيقات) أو الإصدارات الأقدم، نفِّذ سمات مخصّصة وعمليات رجوع مخصّصة لمصدر المظهر:

  • /values/attrs.xml

    <resources>
    <attr name="backgroundRadius" format="dimension" />
    </resources>
    
  • /values/styles.xml

    <resources>
    <style name="MyWidgetTheme">
      <item name="backgroundRadius">@dimen/my_background_radius_dimen</item>
    </style>
    </resources>
    
  • /values-31/styles.xml

    <resources>
    <style name="MyWidgetTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
      <item name="backgroundRadius">@android:dimen/system_app_widget_background_radius</item>
    </style>
    </resources>
    
  • /drawable/my_widget_background.xml

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="?attr/backgroundRadius" />
    </shape>