توفير تنسيقات مرنة للتطبيقات المصغّرة

توضّح هذه الصفحة التحسينات التي تم إجراؤها على حجم التطبيقات المصغّرة وزيادة المرونة التي تم تقديمها في الإصدار 12 من Android (المستوى 31 لواجهة برمجة التطبيقات). ويتضمّن أيضًا تفاصيل حول كيفية تحديد حجم لتطبيقك المصغّر.

استخدام واجهات برمجة تطبيقات محسّنة لأحجام الأدوات والتخطيطات

بدءًا من Android 12 (المستوى 31 من واجهة برمجة التطبيقات)، يمكنك توفير سمات حجم أكثر دقة وتنسيقات مرنة عن طريق اتّباع الخطوات التالية كما هو موضّح في الأقسام التالية:

  1. حدِّد قيودًا إضافية لتغيير حجم التطبيقات المصغّرة.

  2. توفير تنسيقات سريعة الاستجابة أو تنسيقات دقیقة

في الإصدارات السابقة من Android، كان من الممكن الحصول على نطاقات أحجام التطبيقات المصغّرة باستخدام الإضافات OPTION_APPWIDGET_MIN_WIDTH، OPTION_APPWIDGET_MIN_HEIGHT، OPTION_APPWIDGET_MAX_WIDTH، وOPTION_APPWIDGET_MAX_HEIGHT، ثم تقدير حجم التطبيق المصغّر، ولكن لا يعمل هذا المنطق في كل الحالات. بالنسبة إلى التطبيقات المصغّرة التي تستهدف الإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث، ننصحك بتقديم تنسيقات سريعة أو تنسيقات دقيقة.

تحديد قيود إضافية لحجم التطبيقات المصغّرة

يضيف نظام التشغيل Android 12 واجهات برمجة تطبيقات تتيح لك التأكّد من تحديد حجم التطبيقات المصغّرة بشكل أكثر موثوقية على الأجهزة المختلفة التي تختلف أحجام شاشاتها.

بالإضافة إلى سمات minWidth، minHeight، minResizeWidth، وminResizeHeight الحالية، استخدِم سمات appwidget-provider الجديدة التالية:

  • targetCellWidth وtargetCellHeight: حدِّد الحجم المستهدَف لأداة التطبيقات المصغّرة من حيث خلايا شبكة مشغّل التطبيقات. في حال تحديدها، يتم استخدام هاتين السمتَين بدلاً من minWidth أو minHeight.

  • maxResizeWidth وmaxResizeHeight: حدِّد الحد الأقصى للحجم الذي يسمح مشغّل التطبيقات للمستخدم بتغيير حجم التطبيق المصغّر إليه.

يوضح XML التالي كيفية استخدام سمات المقاس.

<appwidget-provider
  ...
  android:targetCellWidth="3"
  android:targetCellHeight="2"
  android:maxResizeWidth="250dp"
  android:maxResizeHeight="110dp">
</appwidget-provider>

توفير تخطيطات سريعة الاستجابة

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

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

يوضّح مثال الرمز البرمجي التالي كيفية تقديم قائمة بالتنسيقات.

Kotlin

override fun onUpdate(...) {
    val smallView = ...
    val tallView = ...
    val wideView = ...

    val viewMapping: Map<SizeF, RemoteViews> = mapOf(
            SizeF(150f, 100f) to smallView,
            SizeF(150f, 200f) to tallView,
            SizeF(215f, 100f) to wideView
    )
    val remoteViews = RemoteViews(viewMapping)

    appWidgetManager.updateAppWidget(id, remoteViews)
}

Java

@Override
public void onUpdate(...) {
    RemoteViews smallView = ...;
    RemoteViews tallView = ...;
    RemoteViews wideView = ...;

    Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
    viewMapping.put(new SizeF(150f, 100f), smallView);
    viewMapping.put(new SizeF(150f, 200f), tallView);
    viewMapping.put(new SizeF(215f, 100f), wideView);
    RemoteViews remoteViews = new RemoteViews(viewMapping);

    appWidgetManager.updateAppWidget(id, remoteViews);
}

لنفترض أنّ التطبيق المصغّر يتضمّن السمات التالية:

<appwidget-provider
    android:minResizeWidth="160dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="200dp">
</appwidget-provider>

يعني مقتطف الرمز السابق ما يلي:

  • يتوافق smallView مع المقاسات من 160dp (minResizeWidth) × 110dp (minResizeHeight) إلى 160dp × 199dp (نقطة الحدّ الأدنى التالية هي 1dp).
  • tallView يتوافق مع 160dp × 200dp إلى 214dp (نقطة الحدّ التالي - 1) × 200dp.
  • يتوافق wideView مع الحجم الذي يتراوح بين 215dp × 110dp (minResizeHeight) و250 (maxResizeWidth) × 200dp (maxResizeHeight).

يجب أن يتوافق التطبيق المصغّر مع نطاق الحجم من minResizeWidth × minResizeHeight إلى maxResizeWidth × maxResizeHeight. وضمن هذا النطاق، يمكنك تحديد نقطة القطع للتبديل بين التنسيقات.

مثال على التنسيق المتجاوب
الشكل 1. مثال على التنسيق المتجاوب

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

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

لتنفيذ هذا الحل، يجب أن ينفِّذ تطبيقك الخطوات التالية:

  1. حدث "الحمولة الزائدة" AppWidgetProvider.onAppWidgetOptionsChanged()، الذي يتم استدعاؤه عند تغيير مجموعة الأحجام

  2. استخدِم AppWidgetManager.getAppWidgetOptions()، الذي يعرض Bundle يحتوي على الأحجام.

  3. يمكنك الوصول إلى مفتاح AppWidgetManager.OPTION_APPWIDGET_SIZES من Bundle.

يوضّح مثال الرمز البرمجي التالي كيفية تقديم تنسيقات دقيقة.

Kotlin

override fun onAppWidgetOptionsChanged(
        context: Context,
        appWidgetManager: AppWidgetManager,
        id: Int,
        newOptions: Bundle?
) {
    super.onAppWidgetOptionsChanged(context, appWidgetManager, id, newOptions)
    // Get the new sizes.
    val sizes = newOptions?.getParcelableArrayList<SizeF>(
            AppWidgetManager.OPTION_APPWIDGET_SIZES
    )
    // Check that the list of sizes is provided by the launcher.
    if (sizes.isNullOrEmpty()) {
        return
    }
    // Map the sizes to the RemoteViews that you want.
    val remoteViews = RemoteViews(sizes.associateWith(::createRemoteViews))
    appWidgetManager.updateAppWidget(id, remoteViews)
}

// Create the RemoteViews for the given size.
private fun createRemoteViews(size: SizeF): RemoteViews { }

Java

@Override
public void onAppWidgetOptionsChanged(
    Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
    super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
    // Get the new sizes.
    ArrayList<SizeF> sizes =
        newOptions.getParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES);
    // Check that the list of sizes is provided by the launcher.
    if (sizes == null || sizes.isEmpty()) {
      return;
    }
    // Map the sizes to the RemoteViews that you want.
    Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
    for (SizeF size : sizes) {
        viewMapping.put(size, createRemoteViews(size));
    }
    RemoteViews remoteViews = new RemoteViews(viewMapping);
    appWidgetManager.updateAppWidget(id, remoteViews);
}

// Create the RemoteViews for the given size.
private RemoteViews createRemoteViews(SizeF size) { }

تحديد حجم التطبيق المصغّر

يجب أن يحدِّد كل تطبيق مصغّر targetCellWidth وtargetCellHeight للأجهزة التي تعمل بالإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث، أو minWidth وminHeight لجميع إصدارات Android، للإشارة إلى الحد الأدنى للمساحة التي يستهلكها التطبيق المصغّر تلقائيًا. ومع ذلك، عندما يضيف المستخدمون أداةً إلى شاشتهم الرئيسية، غالبًا ما تشغل هذه الأداة أكثر من الحدّ الأدنى للعرض والارتفاع اللذان تحدّدهما.

تقدّم شاشات Android الرئيسية للمستخدمين شبكة من المساحات المتاحة التي يمكنهم وضع التطبيقات المصغّرة والرموز عليها. يمكن أن تختلف هذه الشبكة حسب الجهاز، على سبيل المثال، تقدّم العديد من الهواتف المحمولة شبكة 5×4، ويمكن أن تقدّم الأجهزة اللوحية شبكة أكبر. عند إضافة التطبيق المصغّر، يتم تمديده ليشغل الحد الأدنى من الخلايا، أفقيًا وعموديًا، المطلوب لتلبية قيود targetCellWidth وtargetCellHeight على الأجهزة التي تعمل بنظام التشغيل Android 12 أو الإصدارات الأحدث، أو قيود minWidth وminHeight على الأجهزة التي تعمل بنظام التشغيل Android 11 (المستوى 30 لواجهة برمجة التطبيقات) أو الإصدارات الأقدم.

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

عدد الخلايا (العرض × الارتفاع) الحجم المتاح في الوضع العمودي (dp) الحجم المتاح في الوضع الأفقي (dp)
1x1 ‫57×102dp 127×51 بكسل مستقل الكثافة
‫2x1 130×102 بكسل مستقل الكثافة 269×51 بكسل مستقل الكثافة
3×1 ‫203×102dp ‫412x51dp
4×1 ‫276x102dp ‫554x51dp
5×1 ‫349×102dp ‫697×51dp
5×2 349×220 بكسل مستقل الكثافة 697×117 بكسل مستقل الكثافة
5x3 349 × 337 بكسل مستقل الكثافة 697×184 بكسل مستقل الكثافة
5×4 ‫349x455dp ‫697×250dp
... ... ...
n x m ‫(73n - 16) x (118m - 16) ‫(142n - 15) x (66m - 15)

استخدِم أحجام خلايا الوضع العمودي لتحديد القيم التي تقدّمها لسمات minWidth وminResizeWidth وmaxResizeWidth. وبالمثل، استخدِم أحجام الخلايا في الوضع الأفقي لتحديد القيم التي تقدّمها لسمات minHeight وminResizeHeight وmaxResizeHeight.

السبب في ذلك هو أن عرض الخلية عادةً ما يكون أصغر في الوضع الرأسي مقارنة بالوضع الأفقي - وبالمثل، يكون ارتفاع الخلية عادةً أصغر في الوضع الأفقي منه في الوضع الرأسي.

على سبيل المثال، إذا كنت تريد تغيير حجم عرض التطبيق المصغّر إلى خلية واحدة على هاتف Google Pixel 4، يجب ضبط minResizeWidth على 56 بكسل مستقل الكثافة على الأكثر للتأكّد من أنّ قيمة السمة minResizeWidth أصغر من 57 بكسل مستقل الكثافة، لأنّ عرض الخلية لا يقلّ عن 57 بكسل مستقل الكثافة في الوضع العمودي. وبالمثل، إذا كنت تريد أن يكون بإمكان المستخدمين تغيير ارتفاع التطبيق المصغّر في خلية واحدة على الجهاز نفسه، عليك ضبط minResizeHeight على 50dp كحد أقصى للتأكّد من أنّ قيمة سمة minResizeHeight أصغر من 51dp، لأنّ ارتفاع الخلية الواحدة هو 51dp على الأقل في الوضع الأفقي.

يمكن تغيير حجم كل تطبيق مصغّر ضمن نطاقات الحجم بين سمتَي minResizeWidth/minResizeHeight وmaxResizeWidth/maxResizeHeight ، ما يعني أنّه يجب أن يتكيّف مع أي نطاقات حجم بينهما.

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

<appwidget-provider
    android:targetCellWidth="3"
    android:targetCellHeight="2"
    android:minWidth="180dp"
    android:minHeight="110dp">
</appwidget-provider>

وهذا يعني أنّ الحجم التلقائي للتطبيق المصغّر هو 3 خلايا × 2، كما هو محدّد في سمتَي targetCellWidth وtargetCellHeight، أو 180×110dp، كما هو محدّد في سمتَي minWidth وminHeight للأجهزة التي تعمل بالإصدار Android 11 أو إصدارات أقدم. في الحالة الثانية، يمكن أن يختلف الحجم في الخلايا بناءً على الجهاز.

لضبط نطاقات الحجم المتوافقة لأداة التطبيقات المصغّرة، يمكنك أيضًا ضبط السمات التالية:

<appwidget-provider
    android:minResizeWidth="180dp"
    android:minResizeHeight="110dp"
    android:maxResizeWidth="530dp"
    android:maxResizeHeight="450dp">
</appwidget-provider>

وفقًا لما هو محدّد في السمات السابقة، يمكن تغيير حجم عرض التطبيق المصغّر من 180dp إلى 530dp، ويمكن تغيير حجم ارتفاعه من 110dp إلى 450dp. يمكن بعد ذلك تغيير حجم التطبيق المصغّر من 3×2 إلى 5×2 خلية، شرط استيفاء الشروط التالية:

Kotlin

val smallView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_small)
val mediumView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_medium)
val largeView = RemoteViews(context.packageName, R.layout.widget_weather_forecast_large)

val viewMapping: Map<SizeF, RemoteViews> = mapOf(
        SizeF(180f, 110f) to smallView,
        SizeF(270f, 110f) to mediumView,
        SizeF(270f, 280f) to largeView
)

appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(viewMapping))

Java

RemoteViews smallView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_small);
RemoteViews mediumView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_medium);
RemoteViews largeView = 
    new RemoteViews(context.getPackageName(), R.layout.widget_weather_forecast_large);

Map<SizeF, RemoteViews> viewMapping = new ArrayMap<>();
viewMapping.put(new SizeF(180f, 110f), smallView);
viewMapping.put(new SizeF(270f, 110f), mediumView);
viewMapping.put(new SizeF(270f, 280f), largeView);
RemoteViews remoteViews = new RemoteViews(viewMapping);

appWidgetManager.updateAppWidget(id, remoteViews);

لنفترض أنّ التطبيق المصغّر يستخدم التنسيقات المتجاوبة المحدّدة في مقتطفات الرمز البرمجي السابقة. وهذا يعني أنّ التنسيق المحدّد على أنّه R.layout.widget_weather_forecast_small يتم استخدامه من 180dp (minResizeWidth) x 110dp (minResizeHeight) إلى 269x279dp (نقاط القطع التالية - 1). وبالمثل، يُستخدَم الرمزR.layout.widget_weather_forecast_medium من 270x110dp إلى 270x279dp، ويُستخدَم الرمزR.layout.widget_weather_forecast_large من 270x280dp إلى 530dp (maxResizeWidth) x ‏450dp (maxResizeHeight).

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

مثال على تطبيق الطقس المصغّر في أصغر حجم للشبكة 3×2 تعرض واجهة المستخدم
            اسم الموقع الجغرافي (طوكيو) ودرجة الحرارة (14 درجة) ورمز يشير إلى
            طقس غائم جزئيًا.
الشكل 2. ‎3×2 R.layout.widget_weather_forecast_small.

مثال على تطبيق مصغّر للطقس بحجم &quot;متوسط&quot; أبعاده 4×2 يؤدي تغيير حجم التطبيق المصغّر
            بهذه الطريقة إلى إضافة جميع عناصر واجهة المستخدم من حجم التطبيق المصغّر السابق،
            ويضيف التصنيف &quot;غائم جزئيًا&quot; وتوقّعات درجات الحرارة من
            4 مساءً إلى 7 مساءً.
الشكل 3. ‎4×2 R.layout.widget_weather_forecast_medium.

مثال على تطبيق مصغّر للطقس بحجم &quot;متوسط&quot; أبعاده 5×2 يؤدي تغيير حجم التطبيق المصغّر
            بهذه الطريقة إلى ظهور واجهة المستخدم نفسها التي كانت متوفّرة في الحجم السابق، باستثناء أنّه
            يتم تمديده بطول خلية واحدة ليشغل مساحة أفقية أكبر.
الشكل 4. ‎5x2 R.layout.widget_weather_forecast_medium.

مثال على تطبيق مصغّر للطقس بحجم &quot;كبير&quot; أبعاده 5×3 يؤدي تغيير حجم التطبيق المصغّر
            بهذه الطريقة إلى إضافة واجهة مستخدم جديدة إلى أحجام التطبيقات المصغّرة السابقة،
            كما يضيف عرضًا داخل التطبيق المصغّر يحتوي على توقّعات الطقس
            يومي الثلاثاء والأربعاء. رموز تشير إلى الطقس المشمس أو الممطر
            ودرجات الحرارة المرتفعة والمنخفضة لكل يوم
الشكل 5. ‎5×3 R.layout.widget_weather_forecast_large.

مثال على تطبيق مصغّر للطقس بحجم &quot;كبير&quot; أبعاده 5×4 تؤدي إعادة ضبط حجم التطبيق المصغّر
            بهذه الطريقة إلى إضافة جميع عناصر واجهة المستخدم من أحجام التطبيقات المصغّرة السابقة،
            كما تضيف يومَي الخميس والجمعة (ورمزيهما المطابقَين
            اللذَين يشيرَان إلى نوع الطقس بالإضافة إلى أعلى وأقل درجة حرارة
            لكل يوم).
الشكل 6. ‫‎5×4 R.layout.widget_weather_forecast_large.