يواجه المطوّرون غالبًا صعوبات فريدة عند إنشاء تطبيقات للأجهزة القابلة للطي، خاصةً الأجهزة مثل Samsung Trifold أو Pixel Fold الأصلي، الذي يتم فتحه بتنسيق أفقي (rotation_0 = أفقي). تشمل أخطاء المطوّرين ما يلي:
- افتراضات خاطئة بشأن اتجاه الجهاز
- حالات الاستخدام التي يتم تجاهلها
- تعذُّر إعادة احتساب القيم أو تخزينها مؤقتًا عند إجراء تغييرات في الإعدادات
تشمل المشاكل المحدّدة المتعلّقة بالجهاز ما يلي:
- عدم تطابق الاتجاه الطبيعي للجهاز بين الشاشة الخارجية والشاشة الداخلية (افتراضات تستند إلى rotation_0 = الوضع العمودي)، ما يؤدي إلى تعذُّر تشغيل التطبيقات عند طي الجهاز وفتحه
- كثافات الشاشة المختلفة والتعامل غير الصحيح مع تغيير إعدادات الكثافة
- مشاكل في معاينة الكاميرا بسبب اعتماد مستشعر الكاميرا على الاتجاه الطبيعي
لتقديم تجربة مستخدم عالية الجودة على الأجهزة القابلة للطي، ركِّز على المجالات المهمة التالية:
- تحديد اتجاه التطبيق استنادًا إلى مساحة الشاشة الفعلية التي يشغلها التطبيق، وليس استنادًا إلى اتجاه الجهاز
- تعديل معاينات الكاميرا لإدارة اتجاه الجهاز ونِسب العرض إلى الارتفاع بشكل صحيح وتجنُّب المعاينات المنحرفة ومنع الصور الممدودة أو المقتصة
- الحفاظ على استمرارية التطبيق أثناء طي الجهاز أو فتحه من خلال إما الاحتفاظ بالحالة باستخدام
ViewModelأو طرق مشابهة، أو معالجة تغييرات كثافة الشاشة وتغييرات الاتجاه يدويًا، ما يمنع إعادة تشغيل التطبيق أو فقدان الحالة - بالنسبة إلى التطبيقات التي تستخدم مستشعرات الحركة، اضبط نظام الإحداثيات ليتوافق مع الاتجاه الحالي للشاشة وتجنَّب الافتراضات المستندة إلى rotation_0 = الوضع العمودي، ما يضمن تفاعلات دقيقة للمستخدم.
إنشاء تطبيق متكيّف
إذا كان تطبيقك متكيّفًا ويتوافق مع المستوى المحسّن (المستوى 2) الموضّح في إرشادات جودة التطبيقات المتكيّفة، من المفترض أن يعمل التطبيق بشكل جيد على الأجهزة القابلة للطي. في ما عدا ذلك، قبل التحقّق من التفاصيل المحدّدة للأجهزة القابلة للطي ثلاثية الطيات والأجهزة القابلة للطي في الوضع الأفقي، راجِع مفاهيم تطوير التطبيقات المتجاوبة الأساسية التالية على Android.
التنسيقات التكيّفية
يجب أن تتعامل واجهة المستخدم مع أحجام الشاشات المختلفة والتغييرات في نسبة العرض إلى الارتفاع في الوقت الفعلي، مثل فتح الجهاز واستخدام وضع النوافذ المتعددة أو وضع النوافذ على سطح المكتب. اطّلِع على لمحة عن التصاميم التكيّفية للحصول على مزيد من الإرشادات حول كيفية:
- تصميم التنسيقات التكيّفية وتنفيذها
- ضبط التنقّل الأساسي في تطبيقك استنادًا إلى حجم النافذة
- استخدام فئات حجم النافذة لتكييف واجهة مستخدم تطبيقك
- تسهيل تنفيذ التصاميم الأساسية، مثل تصميم القائمة مع التفاصيل، باستخدام واجهات برمجة تطبيقات Jetpack
فئات حجم النافذة
يمكن للأجهزة القابلة للطي، بما في ذلك الأجهزة القابلة للطي في الوضع الأفقي والأجهزة الثلاثية الطي، التبديل بين فئات أحجام النوافذ المضغوطة والمتوسطة والموسّعة على الفور. يضمن فهم هذه الفئات وتنفيذها عرض تطبيقك لعناصر التنقّل وكثافة المحتوى المناسبة لحالة الجهاز الحالية.
يستخدم المثال التالي مكتبة Material 3 المتكيّفة لتحديد المساحة المتاحة للتطبيق من خلال استدعاء الدالة currentWindowAdaptiveInfoV2() أولاً، ثم استخدام التصاميم المناسبة لفئات أحجام النوافذ:
val adaptiveInfo = currentWindowAdaptiveInfoV2()
val windowSizeClass = adaptiveInfo.windowSizeClass
when {
windowSizeClass.isWidthAtLeastBreakpoint(
WIDTH_DP_EXPANDED_LOWER_BOUND
) -> // Expanded
windowSizeClass.isWidthAtLeastBreakpoint(
WIDTH_DP_MEDIUM_LOWER_BOUND
) -> // Medium
else -> // Compact
}
لمزيد من المعلومات، يُرجى الاطّلاع على استخدام فئات حجم النافذة.
جودة التطبيقات التكيّفية
يضمن الالتزام بالمستوى 2 (التطبيق المتكيّف المحسَّن) أو المستوى 1 (التطبيق المتكيّف المميّز) من إرشادات جودة التطبيقات المتكيّفة أن يقدّم تطبيقك تجربة مستخدم جذابة على الأجهزة الثلاثية الطي والأجهزة القابلة للطي في الوضع الأفقي وغيرها من الأجهزة ذات الشاشات الكبيرة. تتضمّن الإرشادات عمليات فحص مهمة على مستويات متعددة للانتقال من تجربة جاهزة للتكيّف إلى تجربة متميّزة.
الإصدار 16 من نظام التشغيل Android والإصدارات الأحدث
بالنسبة إلى التطبيقات التي تستهدف الإصدار Android 16 (مستوى واجهة برمجة التطبيقات 36) والإصدارات الأحدث، يتجاهل النظام القيود المتعلقة باتجاه الشاشة وإمكانية تغيير الحجم ونسبة العرض إلى الارتفاع على الشاشات التي يبلغ أصغر عرض لها 600 وحدة بكسل مستقلة الكثافة أو أكثر. تتوسّع التطبيقات لتملأ نافذة العرض بأكملها، بغض النظر عن نسبة العرض إلى الارتفاع أو اتجاه الشاشة المفضّل لدى المستخدم، ولم يعُد يتم استخدام وضع التوافق لإضافة إطارات سوداء.
اعتبارات خاصة
تتضمّن الأجهزة اللوحية ثلاثية الطيّ والهواتف القابلة للطي ذات الوضع الأفقي سلوكيات فريدة للأجهزة تتطلّب معالجة خاصة، لا سيما فيما يتعلّق بأجهزة الاستشعار ومعاينة الكاميرا واستمرارية الإعدادات (الاحتفاظ بالحالة عند الطيّ أو الفتح أو تغيير الحجم).
معاينة الكاميرا
من المشاكل الشائعة في الأجهزة القابلة للطي ذات الشاشة الأفقية أو في عمليات احتساب نسبة العرض إلى الارتفاع (في سيناريوهات مثل النوافذ المتعددة أو العرض في نافذة على سطح المكتب أو الشاشات المتصلة) ظهور معاينة الكاميرا بشكل ممدود أو جانبي أو مقصوص أو مُدار.
افتراضات غير متطابقة
تحدث هذه المشكلة غالبًا على الأجهزة ذات الشاشات الكبيرة والأجهزة القابلة للطي لأنّ التطبيقات يمكن أن تفترض علاقات ثابتة بين ميزات الكاميرا، مثل نسبة العرض إلى الارتفاع واتجاه المستشعر، وميزات الجهاز، مثل اتجاه الجهاز والاتجاه الطبيعي.
وتتحدى أشكال الأجهزة الجديدة هذا الافتراض. يمكن لجهاز قابل للطي تغيير حجم الشاشة ونسبة العرض إلى الارتفاع بدون تغيير اتجاه دوران الجهاز. على سبيل المثال، يؤدي فتح الجهاز إلى تغيير نسبة العرض إلى الارتفاع، ولكن إذا لم يدوّر المستخدم الجهاز، سيبقى اتجاهه كما هو. إذا افترض أحد التطبيقات أنّ نسبة العرض إلى الارتفاع مرتبطة بتدوير الجهاز، قد يؤدي ذلك إلى تدوير معاينة الكاميرا أو تغيير حجمها بشكل غير صحيح. يمكن أن يحدث الشيء نفسه إذا افترض أحد التطبيقات أنّ اتجاه مستشعر الكاميرا يتطابق مع اتجاه الجهاز في الوضع العمودي، وهو ما لا يكون صحيحًا دائمًا بالنسبة إلى الأجهزة القابلة للطي في الوضع الأفقي.
الحلّ 1: Jetpack CameraX (الأفضل)
أبسط الحلول وأكثرها فعالية هو استخدام مكتبة Jetpack CameraX. تم تصميم عنصر في واجهة المستخدم
PreviewView للتعامل مع جميع تعقيدات المعاينة
تلقائيًا:
- تعدّل
PreviewViewبشكل صحيح اتجاه المستشعر وتدوير الجهاز وتغيير حجمه. - تحافظ هذه السمة على نسبة العرض إلى الارتفاع لصورة الكاميرا، وعادةً ما يتم ذلك من خلال توسيط الصورة واقتصاصها (FILL_CENTER).
- يمكنك ضبط نوع المقياس على
FIT_CENTERلتضمين معاينة في إطار مستطيل إذا لزم الأمر.
لمزيد من المعلومات، راجِع تنفيذ معاينة في مستندات CameraX.
الحلّ 2: CameraViewfinder
إذا كنت تستخدم قاعدة رموز برمجية حالية في Camera2، فإنّ مكتبة CameraViewfinder (متوافقة مع الإصدارات القديمة حتى المستوى 21 لواجهة برمجة التطبيقات) هي حلّ حديث آخر. ويسهّل عرض خلاصة الكاميرا باستخدام TextureView أو SurfaceView وتطبيق جميع عمليات التحويل اللازمة (نسبة العرض إلى الارتفاع والحجم والتدوير) نيابةً عنك.
لمزيد من المعلومات، يُرجى الاطّلاع على مشاركة المدونة تقديم "نافذة عرض الكاميرا" ودليل المطوّر معاينة الكاميرا.
الحلّ 3: استخدام Camera2 يدويًا
إذا تعذّر عليك استخدام CameraX أو CameraViewfinder، عليك احتساب الاتجاه ونسبة العرض إلى الارتفاع يدويًا والتأكّد من تعديل العمليات الحسابية عند كل تغيير في الإعدادات:
- احصل على اتجاه أداة الاستشعار في الكاميرا (على سبيل المثال، 0 أو 90 أو 180 أو 270 درجة) من
CameraCharacteristics. - الحصول على اتجاه العرض الحالي للجهاز (على سبيل المثال، 0 أو 90 أو 180 أو 270 درجة)
- استخدِم هاتين القيمتين لتحديد عمليات التحويل اللازمة لـ
SurfaceViewأوTextureView. - تأكَّد من أنّ نسبة العرض إلى الارتفاع في الناتج
Surfaceتتطابق مع نسبة العرض إلى الارتفاع في معاينة الكاميرا لتجنُّب التشويش. - قد يتم تشغيل تطبيق الكاميرا في جزء من الشاشة، إما في وضع النوافذ المتعددة أو وضع العرض في نافذة على سطح المكتب أو على شاشة عرض متصلة. لهذا السبب، يجب عدم استخدام حجم الشاشة لتحديد أبعاد عدسة الكاميرا، بل يجب استخدام مقاييس النافذة بدلاً من ذلك.
لمزيد من المعلومات، يُرجى الاطّلاع على دليل المطوّرين معاينة الكاميرا والفيديو تطبيق الكاميرا على أشكال مختلفة.
الحلّ 4: تنفيذ إجراءات أساسية باستخدام الكاميرا من خلال هدف
إذا لم تكن بحاجة إلى العديد من ميزات الكاميرا، يمكنك تنفيذ إجراءات أساسية، مثل التقاط صورة أو فيديو باستخدام تطبيق الكاميرا التلقائي على الجهاز. لست بحاجة إلى الدمج مع مكتبة كاميرا، بل يمكنك استخدام Intent.
لمزيد من المعلومات، يُرجى الاطّلاع على أهداف الكاميرا.
الإعداد والاستمرارية
تزيد الأجهزة القابلة للطي من تنوّع واجهة المستخدم، ولكن يمكن أن تؤدي إلى تغييرات في الإعدادات أكثر من الأجهزة غير القابلة للطي. يجب أن يدير تطبيقك تغييرات الضبط هذه ومجموعاتها، مثل تدوير الجهاز والطي/الفتح وتغيير حجم النافذة في وضع النوافذ المتعددة أو وضع سطح المكتب، مع الاحتفاظ بحالة التطبيق أو استعادتها. على سبيل المثال، يجب أن تحافظ التطبيقات على الاستمرارية التالية:
- حالة التطبيق بدون حدوث أعطال أو تغييرات مزعجة للمستخدمين (على سبيل المثال، عند التبديل بين الشاشات أو إرسال التطبيق إلى الخلفية)
- موضع التمرير للحقول القابلة للتمرير
- النص الذي يتم إدخاله في حقول النص وحالة لوحة المفاتيح
- موضع تشغيل الوسائط حتى يتم استئناف التشغيل من حيث توقّف عند بدء تغيير الإعدادات
تشمل تغييرات الإعدادات التي يتم تشغيلها بشكل متكرّر screenSize وsmallestScreenSize وscreenLayout وorientation وdensity وfontScale وtouchscreen وkeyboard.
راجِع android:configChanges والتعامل مع تغييرات الإعدادات. لمزيد من المعلومات حول إدارة حالة التطبيق، يُرجى الاطّلاع على حفظ حالات واجهة المستخدم.
تغييرات إعدادات الكثافة
قد تتضمّن الشاشتان الخارجية والداخلية للأجهزة القابلة للطي ثلاثيًا والأجهزة القابلة للطي في الوضع الأفقي كثافات بكسل مختلفة. لذلك، يجب الانتباه بشكل خاص إلى إدارة تغيير الإعدادات في density. يعيد نظام التشغيل Android عادةً تشغيل النشاط
عندما يتغير معدّل الكثافة على الشاشة، ما قد يؤدي إلى فقدان البيانات. لمنع النظام من إعادة تشغيل النشاط، عليك تعريف معالجة الكثافة في ملف البيان وإدارة تغيير الإعدادات آليًا في تطبيقك.
إعدادات ملف AndroidManifest.xml
density: تحدّد أنّ التطبيق سيتعامل مع تغيير كثافة الشاشة- تغييرات أخرى في الإعدادات: من المفيد أيضًا الإشارة إلى التغييرات الأخرى التي تحدث بشكل متكرر في الإعدادات، مثل
screenSizeوorientationوkeyboardHiddenوfontScaleوما إلى ذلك.
يؤدي تحديد الكثافة (وغيرها من تغييرات الإعدادات) إلى منع النظام من إعادة تشغيل النشاط، ويتم بدلاً من ذلك استدعاء onConfigurationChanged().
تنفيذ onConfigurationChanged()
عند حدوث تغيير في الكثافة، عليك تعديل الموارد (مثل إعادة تحميل الصور النقطية أو إعادة احتساب أحجام التصميم) في دالة الرجوع:
- تأكَّد من تغيير عدد النقاط في البوصة إلى
newConfig.densityDpi - إعادة ضبط طرق العرض المخصّصة والعناصر القابلة للرسم المخصّصة وما إلى ذلك على الكثافة الجديدة
عناصر الموارد المطلوب معالجتها
- مصدر الصورة: استبدِل الصور النقطية والصور القابلة للرسم بموارد خاصة بالكثافة، أو اضبط المقياس مباشرةً
- وحدة التنسيق (تحويل dp إلى px): إعادة احتساب حجم العرض والهامش والحشو
- حجم الخط والنص: إعادة تطبيق حجم النص بوحدة sp
- رسم
View/Canvasمخصّص: تعديل القيم المستندة إلى وحدات البكسل المستخدَمة لرسمCanvas
تحديد اتجاه التطبيق
لا تعتمد أبدًا على تدوير الجهاز الفعلي عند إنشاء تطبيقات متكيّفة، لأنّه سيتم تجاهله على الأجهزة ذات الشاشات الكبيرة، وقد يكون اتجاه التطبيق في وضع النوافذ المتعددة مختلفًا عن اتجاه الجهاز. بدلاً من ذلك، استخدِم Configuration.orientation أو WindowMetrics لتحديد ما إذا كان تطبيقك معروضًا حاليًا بالاتجاه الأفقي أو العمودي استنادًا إلى حجم النافذة.
الحل 1: استخدام Configuration.orientation
تحدّد هذه السمة اتجاه عرض تطبيقك حاليًا.
الحل 2: استخدام WindowMetrics#getBounds()
يمكنك الحصول على حدود العرض الحالية للتطبيق والتحقّق من عرضه وارتفاعه لتحديد اتجاهه.
إذا كنت بحاجة إلى حصر اتجاه التطبيق على الهواتف (أو الشاشات الخارجية للأجهزة القابلة للطي) ولكن ليس على الأجهزة ذات الشاشات الكبيرة، يمكنك الاطّلاع على حصر اتجاه التطبيق على الهواتف وليس على الشاشات الكبيرة.
أوضاع الجهاز وأوضاع العرض
تتوافق الأجهزة القابلة للطي مع أوضاعها وحالاتها، مثل وضع الطاولة وHALF_OPENED، سواء كانت قابلة للطي بشكل عمودي أو أفقي. في المقابل، لا يمكن استخدام الحوامل الثلاثية الطيّ HALF_OPENED لأنّها لا تتيح وضع الجهاز على سطح مستوٍ. في المقابل، توفّر الأجهزة الثلاثية الطي شاشة أكبر لتوفير تجربة فريدة للمستخدم عند فتحها بالكامل.
لتمييز تطبيقك على الأجهزة القابلة للطي التي تتوافق مع HALF_OPENED، استخدِم واجهات برمجة التطبيقات التكيُّفية في Compose Material 3، مثل collectFoldingFeaturesAsState() وcurrentWindowAdaptiveInfoV2().
يمكنك الاطّلاع على مزيد من المعلومات حول أوضاع الأجهزة القابلة للطي وحالاتها ومدى توافقها مع معاينة الكاميرا في أدلة المطوّرين التالية:
توفّر الأجهزة القابلة للطي تجارب مشاهدة فريدة. يتيح لك وضع الشاشة الخلفية ووضع الشاشة المزدوجة إنشاء ميزات عرض خاصة للأجهزة القابلة للطي، مثل معاينة صور السيلفي بالكاميرا الخلفية والعرض المتزامن ولكن المختلف على الشاشتين الداخلية والخارجية. لمزيد من المعلومات، يُرجى الاطّلاع على:
قفل اتجاه الشاشة على اتجاه جهاز الاستشعار الطبيعي
في حالات استخدام محدّدة جدًا، وخاصةً التطبيقات التي تحتاج إلى الاستحواذ على الشاشة بأكملها بغض النظر عن حالة طي الجهاز، يتيح لك الخيار nosensor قفل التطبيق على الاتجاه الطبيعي للجهاز. على سبيل المثال، في هاتف Pixel Fold، يكون اتجاه الجهاز الطبيعي عند طيّه هو الوضع العمودي، بينما يكون اتجاهه الطبيعي عند فتحه هو الوضع الأفقي. تؤدي إضافة العلامة nosensor إلى فرض قفل التطبيق على الوضع العمودي عند تشغيله على الشاشة الخارجية، وعلى الوضع الأفقي عند تشغيله على الشاشة الداخلية.
<activity
android:name=".MainActivity"
android:screenOrientation="nosensor">
إعادة ربط ألعاب وأجهزة استشعار الواقع الممتد
بالنسبة إلى الألعاب وتطبيقات الواقع الممتد، يتم توفير بيانات أجهزة الاستشعار الأولية (مثل الجيروسكوب أو مقياس التسارع) في نظام الإحداثيات الثابتة للجهاز. إذا أدار المستخدم الجهاز لتشغيل لعبة في الوضع الأفقي، لن تدور محاور المستشعر مع الشاشة، ما يؤدي إلى عدم صحة عناصر التحكّم في اللعبة.
لحلّ هذه المشكلة، تحقَّق من قيمة Display.getRotation() الحالية وأعِد ربط المحاور وفقًا لذلك:
- الدوران 0: x=x, y=y
- التدوير بزاوية 90 درجة: x=-y, y=x
- الدوران بمقدار 180 درجة: x=-x, y=-y
- التدوير بمقدار 270 درجة: x=y, y=-x
بالنسبة إلى متجهات الدوران (المستخدَمة في البوصلة أو تطبيقات الواقع الممتد)، استخدِم الدالة SensorManager.remapCoordinateSystem() لربط اتجاه عدسة الكاميرا أو أعلى الشاشة بالمحاور الجديدة استنادًا إلى الدوران الحالي.
توافق التطبيقات
يجب أن تتّبع التطبيقات إرشادات جودة التطبيقات لضمان التوافق مع جميع أشكال الأجهزة والشاشات المتصلة. إذا لم يتمكّن تطبيق من الالتزام بالإرشادات، يمكن لمصنّعي الأجهزة تنفيذ إجراءات توافق، ولكن قد يؤدي ذلك إلى تدهور تجربة المستخدم.
للحصول على معلومات إضافية، راجِع القائمة الشاملة لحلول المشاكل المتعلقة بالتوافق المتوفّرة في النظام الأساسي، وخاصةً تلك المتعلّقة بمعاينة الكاميرا وعمليات الإلغاء والتغييرات في واجهة برمجة التطبيقات Android 16 التي قد تغيّر سلوك تطبيقك.
لمزيد من المعلومات حول إنشاء تطبيقات متجاوبة، يُرجى الاطّلاع على إرشادات جودة التطبيقات المتجاوبة.