دعم النوافذ المتعددة

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

الشكل 1. عرض تطبيقَين جنبًا إلى جنب في وضع تقسيم الشاشة

وتعتمد تجربة المستخدم على إصدار نظام التشغيل Android ونوع الجهاز:

  • يوفّر Android 7.0 (المستوى 24 من واجهة برمجة التطبيقات) وضع تقسيم الشاشة على الأجهزة ذات الشاشات الصغيرة ووضع "نافذة ضمن النافذة" على أجهزة محدّدة.

    يملأ وضع "تقسيم الشاشة" الشاشة بتطبيقَين ويعرضهما إما جنبًا إلى جنب أو أحدهما فوق الآخر. ويمكن للمستخدمين سحب الفاصل الذي يفصل بين التطبيقَين لتكبير أحدهما والآخر تصغيره.

    يتيح وضع "نافذة ضمن النافذة" للمستخدمين مواصلة تشغيل الفيديو أثناء التفاعل مع تطبيق آخر (يمكنك الاطّلاع على إتاحة وضع "نافذة ضمن النافذة").

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

    يمكنك ضبط كيفية تعامل تطبيقك مع وضع النوافذ المتعددة من خلال تحديد الحد الأدنى للأبعاد المسموح بها لنشاطك. يمكنك أيضًا إيقاف وضع النوافذ المتعددة في تطبيقك من خلال ضبط resizeableActivity="false" لضمان أن يعرض النظام التطبيق دائمًا في وضع ملء الشاشة.

  • يعمل Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) على توسيع نطاق وضع "نافذة ضمن النافذة" ليشمل الأجهزة ذات الشاشات الصغيرة.
  • ينفِّذ Android 12 (المستوى 31 من واجهة برمجة التطبيقات) سلوكًا عاديًا لوضع النوافذ المتعددة.

    في الشاشات الكبيرة (sw >= 600dp)، يتيح النظام الأساسي جميع التطبيقات في وضع النوافذ المتعددة بغض النظر عن إعدادات التطبيق. إذا resizeableActivity="false"، يتم إدخال التطبيق في وضع التوافق عند الضرورة لاستيعاب أبعاد العرض.

    على الشاشات الصغيرة (sw < 600dp)، يتحقّق النظام من minWidth و minHeight للنشاط لتحديد ما إذا كان يمكن تشغيله في وضع النوافذ المتعددة. إذا تم استخدام resizeableActivity="false"، سيتم منع تشغيل التطبيق في وضع النوافذ المتعددة بغض النظر عن الحد الأدنى للعرض والارتفاع.

    ملاحظة: يمكن للشركات المصنّعة للأجهزة إلغاء هذه السلوكيات.

وضع تقسيم الشاشة

يمكن للمستخدمين تفعيل وضع تقسيم الشاشة من خلال تنفيذ ما يلي:

  1. افتح شاشة "الأماكن الأخيرة".
  2. تمرير التطبيق سريعًا للعرض
  3. الضغط على رمز التطبيق في شريط عناوين التطبيق
  4. تحديد خيار القائمة في وضع تقسيم الشاشة
  5. اختَر تطبيقًا آخر من شاشة "التطبيقات الأخيرة"، أو أغلق شاشة "التطبيقات الأخيرة" وشغِّل تطبيقًا آخر.

يمكن للمستخدمين الخروج من وضع تقسيم الشاشة عن طريق سحب أداة تقسيم النوافذ إلى حافة الشاشة - لأعلى أو لأسفل أو لليسار أو اليمين.

تشغيل العنصر في مكان مجاور

إذا كان تطبيقك يحتاج إلى الوصول إلى المحتوى من خلال غرض، يمكنك استخدام FLAG_ACTIVITY_LAUNCH_ADJACENT لفتح المحتوى في نافذة مجاورة مقسَّمة للشاشة.

تم طرح FLAG_ACTIVITY_LAUNCH_ADJACENT في نظام التشغيل Android 7.0 (المستوى 24 من واجهة برمجة التطبيقات) للسماح للتطبيقات التي يتم تشغيلها في وضع تقسيم الشاشة ببدء الأنشطة في النافذة المجاورة.

لقد تم توسيع نطاق تعريف العلم في نظام التشغيل Android 12L (المستوى 32 من واجهة برمجة التطبيقات) والإصدارات الأحدث لإتاحة تفعيل وضع تقسيم الشاشة للتطبيقات التي تعمل في وضع ملء الشاشة ثم بدء الأنشطة في النافذة المجاورة.

لتشغيل نشاط مجاور، استخدِم FLAG_ACTIVITY_LAUNCH_ADJACENT إلى جانب FLAG_ACTIVITY_NEW_TASK، على سبيل المثال:

Kotlin

fun openUrlInAdjacentWindow(url: String) {
    Intent(Intent.ACTION_VIEW).apply {
        data = Uri.parse(url)
        addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT or
                           Intent.FLAG_ACTIVITY_NEW_TASK)
    }.also { intent ->
        startActivity(intent)
    }
}

Java

public void openUrlInAdjacentWindow(String url) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse(url));
    intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
}

مراحل نشاط النشاط في وضع النوافذ المتعددة

لا يؤدي وضع النوافذ المتعددة إلى تغيير مراحل نشاط النشاط. ومع ذلك، تختلف الحالة الاستئنافية للتطبيقات في نوافذ متعددة على إصدارات مختلفة من Android.

السيرة الذاتية المتعدّدة

يتيح Android 10 (المستوى 29 من واجهة برمجة التطبيقات) والإصدارات الأحدث ميزة الاستئناف المتعدد، وتظل جميع الأنشطة في حالة RESUMED عندما يكون الجهاز في وضع النوافذ المتعددة. يمكن إيقاف النشاط مؤقتًا إذا كان النشاط الشفاف أعلى النشاط أو كان النشاط غير قابل للتركيز، على سبيل المثال، وضع "نافذة ضمن النافذة". ومن الممكن أيضًا ألا يتم التركيز على أي نشاط في وقت معين، مثلاً إذا كان درج الإشعارات مفتوحًا. تعمل طريقة onStop كالمعتاد، وتُسمى الطريقة في أي وقت يتم فيه إزالة نشاط من الشاشة.

تتوفّر أيضًا ميزة السيرة الذاتية المتعدّدة على أجهزة محدَّدة تعمل بنظام التشغيل Android 9 (المستوى 28 من واجهة برمجة التطبيقات). لتفعيل السيرة الذاتية المتعدّدة على أجهزة Android 9، أضِف البيانات الوصفية التالية:

<meta-data android:name="android.allow_multiple_resumed_activities" android:value="true" />

للتحقّق من توافق جهاز معيّن مع البيانات الوصفية لهذا البيان، عليك الرجوع إلى مواصفات الجهاز.

الإصدار 9 من نظام التشغيل Android

في وضع النوافذ المتعددة على نظام التشغيل Android 9 (المستوى 28 لواجهة برمجة التطبيقات) والإصدارات الأقدم، لا يتم تفعيل سوى النشاط الذي تفاعل معه المستخدم مؤخرًا في وقت معيَّن. يُعتبر هذا النشاط في أعلى الصفحة، وهو النشاط الوحيد في حالة RESUMED. جميع الأنشطة المرئية الأخرى هي STARTED ولكنها ليست RESUMED. ومع ذلك، يمنح النظام هذه الأنشطة المرئية ولكن غير المستأنفة أولوية أعلى من الأنشطة غير المرئية. وإذا تفاعل المستخدم مع أحد الأنشطة المرئية، يتم استئناف هذا النشاط ويدخل النشاط الأعلى في السابق في حالة STARTED.

عندما تكون هناك أنشطة متعددة ضمن عملية تطبيق نشطة واحدة، يتم استئناف النشاط بأعلى ترتيب z، ويتم إيقاف الأنشطة الأخرى مؤقتًا.

تغييرات الإعدادات

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

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

إذا كان المستخدم يغيّر حجم نافذة وجعلها أكبر في أي من البعدين، سيغيّر النظام حجم النشاط ليلائم إجراء المستخدم، ويتغيّر في الإعدادات حسب الحاجة. إذا تأخّر التطبيق في الرسم في مناطق مكشوفة حديثًا، يملأ النظام هذه المناطق مؤقتًا باللون المحدّد في السمة windowBackground أو حسب سمة النمط windowBackgroundFallback التلقائية.

الوصول الحصري إلى المراجع

للمساعدة في دعم ميزة الاستئناف المتعدّد، هناك معاودة اتصال جديدة بمراحل نشاط، onTopResumedActivityChanged().

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

Kotlin

override fun onTopResumedActivityChanged(topResumed: Boolean) {
    if (topResumed) {
        // Top resumed activity
        // Can be a signal to re-acquire exclusive resources
    } else {
        // No longer the top resumed activity
    }
}

Java

@Override
public void onTopResumedActivityChanged(boolean topResumed) {
    if (topResumed) {
        // Top resumed activity
        // Can be a signal to re-acquire exclusive resources
    } else {
        // No longer the top resumed activity
    }
}

وتجدُر الإشارة إلى أنّه يمكن أن يفقد التطبيق الموارد لأسباب أخرى، مثل إزالة جهاز مشترَك.

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

بالنسبة إلى التطبيقات التي تستخدم كاميرا، تقدّم CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged() تلميحًا إلى أنّه قد يكون الوقت مناسبًا لمحاولة الوصول إلى الكاميرا. تتوفّر هذه الطريقة اعتبارًا من نظام التشغيل Android 10 (المستوى 29 من واجهة برمجة التطبيقات).

يُرجى العِلم أنّ تطبيق resizeableActivity=false لا يضمن الوصول الحصري إلى الكاميرا، لأنّه يمكن فتح التطبيقات الأخرى التي تستخدم الكاميرا على شاشات أخرى.

الكاميرا في وضع النوافذ المتعددة.

الشكل 2. الكاميرا في وضع النوافذ المتعددة.

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

بعد أن يتلقّى التطبيق معاودة الاتصال بـ CameraDevice.StateCallback#onDisconnected()، ستؤدي المكالمات اللاحقة على جهاز الكاميرا إلى عرض رمز الخطأ CameraAccessException.

شاشات متعددة

يتوافق Android 10 (المستوى 29 من واجهة برمجة التطبيقات) مع الأنشطة على الشاشات الثانوية. في حال تشغيل نشاط على جهاز يتضمن شاشات متعددة، يمكن للمستخدمين نقل النشاط من شاشة إلى أخرى. ينطبق السيرة الذاتية المتعددة على سيناريوهات الشاشات المتعددة أيضًا؛ يمكن أن تتلقى العديد من الأنشطة مدخلات المستخدم في نفس الوقت.

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

عندما ينتقل نشاط إلى شاشة ثانوية، يمكن أن يمر عبر تحديث السياق وتغيير حجم النوافذ وتغييرات في الإعدادات والموارد. إذا كان النشاط يشمل تغيير الإعدادات، يتم إشعار النشاط في onConfigurationChanged()، وإلا ستتم إعادة تشغيل النشاط.

ويجب أن يتحقّق النشاط من الشاشة الحالية في onCreate وonConfigurationChanged في حال التعامل مع تغيير الإعدادات. تأكد من تحديث الموارد والتخطيطات عند تغيير العرض.

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

نُسخ متعددة من نشاط على شاشات عرض متعددة

الشكل 3. نُسخ متعددة من نشاط على شاشات عرض متعددة

يمكنك أيضًا الاطلاع على واجهات برمجة التطبيقات للشاشات المتعددة التي تم تقديمها في Android 8.0.

سياق النشاط مقابل التطبيق

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

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

تحدد تهيئة نافذة النشاط والعرض الرئيسي الموارد والسياق. يمكنك الحصول على الشاشة الحالية على النحو التالي:

Kotlin

val activityDisplay = activity.getDisplay()

Java

Display activityDisplay = activity.getDisplay();

الحصول على مقاييس فترة النشاط الحالية:

Kotlin

val windowMetrics = activity.getWindowManager().getCurrentWindowMetrics()

Java

WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();

يمكنك الحصول على الحد الأقصى لمقاييس الفترات الزمنية لضبط النظام الحالي:

Kotlin

val maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics()

Java

WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();

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

خطوط عرض

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

الشاشات الثانوية

يمكنك الحصول على الشاشات المتوفّرة من خدمة نظام DisplayManager:

Kotlin

val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val displays = displayManager.getDisplays()

Java

DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
Display[] displays = displayManager.getDisplays();

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

لتحديد ما إذا كان يمكن بدء نشاط على شاشة أم لا:

Kotlin

val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent)

Java

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
boolean activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent);

بعد ذلك، ابدأ النشاط على الشاشة:

Kotlin

val options = ActivityOptions.makeBasic()
options.setLaunchDisplayId(targetDisplay.displayId)
startActivity(intent, options.toBundle())

Java

ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(targetDisplay.displayId);
startActivity(intent, options.toBundle());

دعم الشاشات المتعددة

يوفر Android دعم شاشات متعددة للوحات المفاتيح البرمجية والخلفيات ومشغّلات التطبيقات.

لوحة مفاتيح برمجية

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

لوحة المفاتيح على شاشة ثانوية

الشكل 4. لوحة المفاتيح على شاشة ثانوية

الخلفية

في نظام Android 10 (المستوى 29 من واجهة برمجة التطبيقات)، يمكن أن تتوفّر خلفية للشاشات الثانوية. وينشئ إطار العمل مثيلاً منفصلاً من WallpaperService.Engine لكل عرض. احرص على رسم سطح كل محرك بشكل مستقل. يمكن للمطوّرين تحميل مواد العرض باستخدام سياق العرض في WallpaperService.Engine#getDisplayContext(). احرص أيضًا على إدراج مجموعات ملفات WallpaperInfo.xml android:supportsMultipleDisplays="true".

الخلفية على الهاتف والشاشة الثانوية

الشكل 5. الخلفية على الهاتف والشاشة الثانوية

مشغّلات التطبيقات

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

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

يجب أن يتضمّن النشاط وضع تشغيل لا يمنع ظهور نُسخ متعددة ويمكن أن يتكيّف مع أحجام الشاشات المختلفة. لا يمكن أن يكون وضع التشغيل singleInstance أو singleTask.

على سبيل المثال، يسمح تنفيذ AOSP لـ Launcher3 بنشاط SECONDARY_HOME.

مشغّل التطبيقات Material Design على الهاتف

الشكل 6. مشغّل التطبيقات Material Design على الهاتف

مشغّل التطبيقات Material Design على شاشة ثانوية

الشكل 7. مشغّل التطبيقات Material Design على شاشة ثانوية

مقاييس الفترات

قدّم Android 11 (المستوى 30 لواجهة برمجة التطبيقات) طُرق WindowManager التالية لتوفير حدود التطبيقات التي تعمل في وضع النوافذ المتعددة:

توفّر طُرق مكتبة Jetpack WindowManager computeCurrentWindowMetrics() وcomputeMaximumWindowMetrics() وظائف مماثلة على التوالي، ولكن تتوافق مع الأنظمة القديمة مع المستوى 14 من واجهة برمجة التطبيقات.

للحصول على مقاييس لشاشات العرض بخلاف الشاشة الحالية، يمكنك إجراء ما يلي:

  • إنشاء سياق العرض
  • إنشاء سياق نافذة للعرض
  • الحصول على WindowManager لسياق النافذة
  • احصل على WindowMetrics لأقصى مساحة عرض متاحة للتطبيق.

Kotlin

val windowMetrics = context.createDisplayContext(display)
                    .createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
                    .getSystemService(WindowManager::class.java)
                    .maximumWindowMetrics

Java

WindowMetrics windowMetrics = context.createDisplayContext(display)
                              .createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
                              .getSystemService(WindowManager.class)
                              .getMaximumWindowMetrics();

الطرق التي تم إيقافها نهائيًا

تم إيقاف طرق Display getSize() وgetMetrics() في المستوى 30 من واجهة برمجة التطبيقات لصالح طرق WindowManager الجديدة.

يوقِف نظام التشغيل Android 12 (المستوى 31 من واجهة برمجة التطبيقات) نهائيًا Display طرق getRealSize() وgetRealMetrics() ويعدّل سلوكها لتتطابق مع سلوك getMaximumWindowMetrics() بشكل أكبر.

إعدادات وضع النوافذ المتعددة

إذا كان تطبيقك يستهدف الإصدار 7.0 من نظام التشغيل Android (المستوى 24 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكنك ضبط كيفية عمل تطبيقك وما إذا كانت أنشطة تطبيقك تتوافق مع وضع النوافذ المتعددة. يمكنك ضبط السمات في ملف البيان للتحكّم في الحجم والتنسيق. تنطبق إعدادات سمة النشاط الجذر على جميع الأنشطة ضمن حزمة المهام الخاصة به. على سبيل المثال، إذا كان النشاط الجذر يحتوي على android:resizeableActivity="true"، يمكن تغيير حجم جميع الأنشطة في حزمة المهام. على بعض الأجهزة الأكبر حجمًا، مثل أجهزة Chromebook، قد يتم تشغيل تطبيقك في نافذة يمكن تغيير حجمها حتى في حال تحديد android:resizeableActivity="false". إذا كان هذا سيؤدي إلى إيقاف تطبيقك، يمكنك استخدام الفلاتر لتقييد مدى توفّر تطبيقك على هذه الأجهزة.

الإعداد التلقائي لنظام التشغيل Android 12 (المستوى 31 لواجهة برمجة التطبيقات) هو وضع النوافذ المتعددة. في الشاشات الكبيرة (sw >= 600dp)، تعمل جميع التطبيقات في وضع النوافذ المتعددة بغض النظر عن إعدادات التطبيق. على الشاشات الصغيرة، يتحقّق النظام من إعدادات minWidth وminHeight وresizeableActivity للنشاط لتحديد ما إذا كان يمكن تشغيله في وضع النوافذ المتعددة.

نشاط قابل لتغيير الحجم

اضبط هذه السمة في عنصر <activity> أو عنصر <application> في البيان لتفعيل وضع النوافذ المتعددة أو إيقافه للمستوى 30 لواجهة برمجة التطبيقات أو المستوى الأدنى منه:

<application
  android:name=".MyActivity"
  android:resizeableActivity=["true" | "false"] />

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

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

إذا كان تطبيقك يستهدف المستوى 31 من واجهة برمجة التطبيقات أو المستويات الأعلى، ستعمل هذه السمة بشكل مختلف على الشاشات الصغيرة والكبيرة:

  • الشاشات الكبيرة (sw >= 600dp): تتيح جميع التطبيقات وضع النوافذ المتعددة. تشير السمة إلى ما إذا كان يمكن تغيير حجم النشاط أم لا. وإذا resizeableActivity="false"، يتم إدراج التطبيق في وضع التوافق عندما يكون ذلك ضروريًا للتوافق مع أبعاد العرض.
  • الشاشات الصغيرة (sw < 600dp): إذا كان resizeableActivity="true" والحد الأدنى للعرض والنشاط ضمن متطلبات النوافذ المتعددة، يتيح النشاط وضع النوافذ المتعددة. إذا كان resizeableActivity="false"، لا يتيح النشاط وضع النوافذ المتعددة بغض النظر عن الحد الأدنى للعرض والارتفاع الخاص بالنشاط.

متوافق مع PictureInPicture

اضبط هذه السمة في عقدة <activity> الخاصة بالبيان للإشارة إلى ما إذا كان النشاط يتيح وضع "نافذة ضمن النافذة".

<activity
  android:name=".MyActivity"
  android:supportsPictureInPicture=["true" | "false"] />

تغييرات config

لمعالجة التغييرات التي يتم إجراؤها على إعدادات النوافذ المتعددة بنفسك، مثلاً عندما يغيِّر المستخدم حجم النافذة، أضِف السمة android:configChanges إلى عقدة بيان التطبيق <activity> مع القيم التالية على الأقل:

<activity
  android:name=".MyActivity"
  android:configChanges="screenSize | smallestScreenSize
      | screenLayout | orientation" />

بعد إضافة android:configChanges، يتم استدعاء نشاطك وأجزائه إلى onConfigurationChanged() بدلاً من تدميرها وإعادة إنشائها. يمكنك بعد ذلك تحديث طرق العرض يدويًا، وإعادة تحميل الموارد، وإجراء عمليات أخرى حسب الحاجة.

<layout>

في نظام التشغيل Android 7.0 (المستوى 24 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يتوافق عنصر البيان <layout> مع سمات متعدّدة تؤثّر في سلوك النشاط في وضع النوافذ المتعددة:

android:defaultHeight، android:defaultWidth
الارتفاع والعرض التلقائي للنشاط عند تشغيله في وضع التصميم المرن.
android:gravity
الموضع الأول للنشاط عند إطلاقه في وضع التصميم المرن. راجِع Gravity للاطّلاع على القيم المناسبة.
android:minHeight، android:minWidth
الحد الأدنى للارتفاع والحد الأدنى لعرض النشاط في كل من وضع "تقسيم الشاشة" والوضع الحر. إذا نقل المستخدم الفاصل في وضع تقسيم الشاشة لتقليل الحدّ الأدنى المسموح به للنشاط، سيقتطع النظام النشاط وفقًا للحجم الذي يطلبه المستخدم.

يوضح الرمز التالي كيفية تحديد الحجم والموقع الافتراضي للنشاط والحد الأدنى لحجمه عند عرض النشاط في وضع التصميم الحر:

<activity android:name=".MyActivity">
    <layout android:defaultHeight="500dp"
          android:defaultWidth="600dp"
          android:gravity="top|end|..."
          android:minHeight="450dp"
          android:minWidth="300dp" />
</activity>

وضع النوافذ المتعددة في وقت التشغيل

بدءًا من نظام التشغيل Android 7.0، سيقدّم النظام وظائف تتوافق مع التطبيقات التي يمكن تشغيلها في وضع النوافذ المتعددة.

الميزات غير المفعّلة في وضع النوافذ المتعددة

في وضع النوافذ المتعددة، قد يوقف Android أو يتجاهل الميزات التي لا تنطبق على نشاط يشارك شاشة الجهاز مع أنشطة أو تطبيقات أخرى.

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

يتجاهل النظام التغييرات التي يتم إجراؤها على السمة android:screenOrientation.

الطلبات وعمليات معاودة الاتصال في وضع النوافذ المتعددة

تقدّم الفئة Activity الطرق التالية لإتاحة وضع النوافذ المتعددة:

isInMultiWindowMode()
يشير إلى ما إذا كان النشاط في وضع النوافذ المتعددة.
isInPictureInPictureMode()

تشير هذه السمة إلى ما إذا كان النشاط في وضع "نافذة ضمن النافذة".

ملاحظة: وضع "نافذة ضمن النافذة" هو حالة خاصة لوضع النوافذ المتعددة. إذا كانت قيمة myActivity.isInPictureInPictureMode() تعرض القيمة "صحيح"، ستعرِض الدالة myActivity.isInMultiWindowMode() أيضًا القيمة "صحيح".

onMultiWindowModeChanged()
يستدعي النظام هذه الطريقة عندما يدخل النشاط في وضع النوافذ المتعددة أو يخرج منه. يمرِّر النظام القيمة "صحيح" إذا كان النشاط يدخل في وضع النوافذ المتعددة أو على "خطأ" إذا كان النشاط يغادر وضع النوافذ المتعددة.
onPictureInPictureModeChanged()
يستدعي النظام هذه الطريقة عند دخول النشاط في وضع "نافذة ضمن النافذة" أو خارجه. يمرِّر النظام القيمة "صحيح" إذا دخول النشاط في وضع "نافذة ضمن النافذة" أو "خطأ" إذا كان النشاط خارج وضع "نافذة ضمن النافذة".

تعرض الفئة Fragment نُسخًا من العديد من هذه الطرق، على سبيل المثال، Fragment.onMultiWindowModeChanged().

وضع "نافذة ضمن النافذة"

لتفعيل وضع "نافذة ضمن النافذة" لنشاط، اتصِل بـ enterPictureInPictureMode() ليس لهذه الطريقة أي تأثير إذا لم يكن الجهاز يتيح استخدام وضع "نافذة ضمن النافذة". لمزيد من المعلومات، يُرجى الاطّلاع على دعم الميزة "نافذة ضمن النافذة".

أنشطة جديدة في وضع النوافذ المتعددة

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

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

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

يتيح نظام Android 12 (المستوى 31 من واجهة برمجة التطبيقات) للتطبيقات تقسيم نافذة مهام التطبيق بين أنشطة متعددة. يمكنك تحديد الطريقة التي يعرض بها تطبيقك أنشطته، سواء في وضع ملء الشاشة أو جنبًا إلى جنب أو في حزمة، من خلال إنشاء ملف إعداد XML أو إجراء طلبات بيانات من واجهة برمجة التطبيقات Jetpack WindowManager.

سحب وإفلات

يمكن للمستخدمين سحب البيانات وإفلاتها من نشاط إلى آخر أثناء مشاركة النشاطين للشاشة. (قبل الإصدار 7.0 من نظام التشغيل Android، كان بإمكان المستخدمين سحب البيانات وإفلاتها فقط في نشاط واحد). لإتاحة إمكانية قبول المحتوى الذي تم استبعاده بشكل سريع، راجِع واجهة برمجة تطبيقات DropHelper. للحصول على إرشادات شاملة حول السحب والإفلات، راجِع السحب والإفلات.

الأحداث المتعدّدة

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

يتيح لك نظام التشغيل Android 12 (المستوى 31 من واجهة برمجة التطبيقات) تشغيل مثيلين من النشاط جنبًا إلى جنب في نافذة المهام نفسها.

إذا كنت تريد السماح للمستخدمين ببدء نسخة أخرى من تطبيقك من مشغِّل التطبيقات أو شريط التطبيقات، تأكَّد من ضبط رمز النشاط في مشغّل التطبيقات android:resizeableActivity="true" ولا يستخدم وضع تشغيل يمنع حدوث عدة مثيلات. على سبيل المثال، يمكن إنشاء مثيل لنشاط singleInstancePerTask عدة مرات في مهام مختلفة عند ضبط FLAG_ACTIVITY_MULTIPLE_TASK أو FLAG_ACTIVITY_NEW_DOCUMENT.

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

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

التأكّد من وضع النوافذ المتعددة

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

أجهزة الاختبار

تتوافق الأجهزة التي تعمل بالإصدار 7.0 من نظام التشغيل Android (المستوى 24 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث مع وضع النوافذ المتعددة.

المستوى 23 من واجهة برمجة التطبيقات أو المستوى الأدنى

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

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

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

مستويات واجهة برمجة التطبيقات من 24 إلى 30

إذا كان تطبيقك يستهدف المستويات من 24 إلى 30 لواجهة برمجة التطبيقات ولا يوقِف إتاحة النوافذ المتعددة، تحقَّق من السلوك التالي في وضعَي "تقسيم الشاشة" و"الشكل المرن":

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

المستوى 31 من واجهة برمجة التطبيقات أو أعلى

إذا كان تطبيقك يستهدف المستوى 31 أو أعلى لواجهة برمجة التطبيقات وكان الحد الأدنى للعرض والحد الأدنى للارتفاع للنشاط الرئيسي أقل من أو مساوٍ للأبعاد المعنية لمساحة العرض المتاحة، تحقَّق من جميع السلوكيات المذكورة لمستويات واجهة برمجة التطبيقات من 24 إلى 30.

قائمة التحقق للاختبار

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

  • الدخول في وضع النوافذ المتعددة والخروج منه
  • بدِّل من تطبيقك إلى تطبيق آخر، وتحقَّق من أن التطبيق يعمل بشكلٍ صحيح عندما يكون مرئيًا لكنه غير نشط. على سبيل المثال، إذا كان تطبيقك يشغّل فيديو، تأكَّد من مواصلة تشغيله أثناء تفاعل المستخدم مع تطبيق آخر.
  • في وضع تقسيم الشاشة، جرِّب تحريك أداة تقسيم الشاشة لجعل تطبيقك أكبر حجمًا وأصغر حجمًا. جرِّب هذه العمليات جنبًا إلى جنب مع عملية واحدة فوق الإعدادات الأخرى. تأكَّد من أنّ التطبيق لا يتعطّل وأنّ الوظائف الأساسية ظاهرة وأنّ عملية تغيير الحجم لا تستغرق وقتًا طويلاً.
  • تنفيذ عدة عمليات لتغيير الحجم بتتابع سريع يُرجى التأكّد من عدم تعطُّل تطبيقك أو تسرُّب الذاكرة. يوفّر محلّل الذاكرة في "استوديو Android" معلومات حول استخدام تطبيقك للذاكرة (راجِع فحص استخدام تطبيقك للذاكرة باستخدام Memory Profiler).
  • استخدِم تطبيقك بشكل طبيعي في عدد من عمليات ضبط النوافذ المختلفة، وتأكَّد من أنّ التطبيق يعمل بشكل صحيح. تأكَّد من أنّ النص قابل للقراءة ومن أنّ عناصر واجهة المستخدم ليست صغيرة جدًا بحيث لا يمكن التفاعل معها.

تم إيقاف إمكانية النوافذ المتعددة

في مستويات واجهة برمجة التطبيقات من 24 إلى 30، في حال إيقاف إتاحة النوافذ المتعددة من خلال ضبط android:resizeableActivity="false"، عليك تشغيل التطبيق على جهاز يعمل بالإصدار 7.0 إلى الإصدار 11 من نظام التشغيل Android ومحاولة وضع التطبيق في وضعَي الشاشة المنقسمة والشكل الحر. تحقق من أنه عند القيام بذلك، يظل التطبيق في وضع ملء الشاشة.

مراجع إضافية

لمزيد من المعلومات عن إتاحة النوافذ المتعددة في Android، يُرجى الاطّلاع على: