التوافق مع الأجهزة القابلة للطي ثلاثية الطيات والأجهزة القابلة للطي في الوضع الأفقي

هاتف قابل للطي في الوضع الأفقي في وضعيتَي الإغلاق والفتح الكامل بجانب هاتف ثلاثي الطي في وضعيتَي الإغلاق والفتح الكامل

يواجه المطوّرون غالبًا صعوبات فريدة عند إنشاء تطبيقات للأجهزة القابلة للطي، لا سيما الأجهزة مثل Samsung Trifold أو Pixel Fold الأصلي الذي يفتح بتنسيق أفقي (rotation_0 = أفقي). تشمل أخطاء المطوّرين ما يلي:

  • افتراضات خاطئة حول اتجاه الجهاز
  • حالات استخدام تم تجاهلها
  • عدم إعادة احتساب القيم أو تخزينها مؤقتًا عند إجراء تغييرات في الإعدادات

تشمل المشاكل المحدّدة المتعلّقة بالجهاز ما يلي:

  • عدم تطابق الاتجاه الطبيعي للجهاز بين الشاشتَين الخارجية والداخلية (افتراضات تستند إلى rotation_0 = عمودي)، ما يؤدي إلى تعذُّر عمل التطبيقات عند طي الجهاز وفتحه
  • كثافات شاشة مختلفة ومعالجة غير صحيحة لتغيير إعدادات الكثافة
  • مشاكل في معاينة الكاميرا ناتجة عن اعتماد مستشعر الكاميرا على الاتجاه الطبيعي

لتقديم تجربة مستخدم عالية الجودة على الأجهزة القابلة للطي، ركِّز على المجالات المهمة التالية:

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

إنشاء تطبيقات متكيّفة

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

التنسيقات التكيّفية

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

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

فئات أحجام النوافذ

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

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

يستخدِم المثال التالي مكتبة Material 3 التكيّفية لتحديد مقدار المساحة المتاحة للتطبيق من خلال استدعاء الدالة currentWindowAdaptiveInfo() أولاً، ثم استخدام التنسيقات المقابلة لفئات أحجام النوافذ الثلاث:

val adaptiveInfo = currentWindowAdaptiveInfo()
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 (التطبيق المتكيّف المميّز) من إرشادات جودة التطبيقات المتكيّفة أن يقدّم تطبيقك تجربة مستخدم جذابة على الأجهزة القابلة للطي ثلاثية الأجزاء والأجهزة القابلة للطي الأفقية، والأجهزة الأخرى ذات الشاشات الكبيرة. تغطّي الإرشادات عمليات التحقّق المهمة على مستوى فئات متعددة للانتقال من تطبيق جاهز للتكيّف إلى تجربة مميّزة.

الإصدار Android 16 والإصدارات الأحدث

بالنسبة إلى التطبيقات التي تستهدف الإصدار Android 16 (المستوى 36 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يتجاهل النظام قيود الاتجاه وتغيير الحجم ونسبة العرض إلى الارتفاع على الشاشات التي يبلغ عرضها الأصغر 600dp أو أكثر. تملأ التطبيقات نافذة العرض بأكملها، بغض النظر عن نسبة العرض إلى الارتفاع أو الاتجاه المفضّل لدى المستخدم، ولم يعُد يتم استخدام وضع التوافق المحاط بـإطار.

اعتبارات خاصة

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

معاينة الكاميرا

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

افتراضات غير متطابقة

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

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

الحل 1: Jetpack CameraX (الأفضل)

أبسط الحلول وأكثرها فعالية هو استخدام مكتبة Jetpack CameraX. تم تصميم عنصر واجهة المستخدم PreviewView للتعامل مع جميع تعقيدات المعاينة تلقائيًا:

  • يضبط PreviewView بشكلٍ صحيح اتجاه المستشعر واتجاه الجهاز وتغيير الحجم.
  • يحافظ على نسبة العرض إلى الارتفاع لصورة الكاميرا، عادةً من خلال توسيطها واقتصاصها (FILL_CENTER).
  • يمكنك ضبط نوع المقياس على FIT_CENTER لإضافة إطار إلى المعاينة إذا لزم الأمر.

لمزيد من المعلومات، راجِع مقالة تنفيذ معاينة في مستندات CameraX.

الحل 2: CameraViewfinder

إذا كنت تستخدِم قاعدة بيانات حالية لـ Camera2، فإنّ مكتبة CameraViewfinder (المتوافقة مع الإصدارات السابقة حتى المستوى 21 من واجهة برمجة التطبيقات) هي حلّ حديث آخر. تُبسّط هذه المكتبة عرض بيانات الكاميرا من خلال استخدام TextureView أو SurfaceView وتطبيق جميع عمليات التحويل اللازمة (نسبة العرض إلى الارتفاع والمقياس والاتجاه) نيابةً عنك.

لمزيد من المعلومات، راجِع منشور المدونة Introducing Camera Viewfinder و دليل المطوّر لـ معاينة الكاميرا.

الحل 3: تنفيذ Camera2 يدويًا

إذا لم تتمكّن من استخدام CameraX أو CameraViewfinder، عليك احتساب الاتجاه ونسبة العرض إلى الارتفاع يدويًا والتأكّد من تعديل عمليات الاحتساب عند كل تغيير في الإعدادات:

  • احصل على اتجاه مستشعر الكاميرا (على سبيل المثال، 0 أو 90 أو 180 أو 270 درجة) من CameraCharacteristics.
  • احصل على اتجاه العرض الحالي للجهاز (على سبيل المثال، 0 أو 90 أو 180 أو 270 درجة).
  • استخدِم هاتَين القيمتَين لتحديد عمليات التحويل اللازمة لـ SurfaceView أو TextureView.
  • تأكَّد من أنّ نسبة العرض إلى الارتفاع لـ Surface الناتج تتطابق مع نسبة العرض إلى الارتفاع لمعاينة الكاميرا لمنع حدوث تشويه.
  • قد يتم تشغيل تطبيق الكاميرا في جزء من الشاشة، إما في وضع النوافذ المتعددة أو وضع العرض في نافذة أو على شاشة متصلة. لهذا السبب، يجب عدم استخدام حجم الشاشة لتحديد أبعاد عدسة الكاميرا، بل استخدِم مقاييس النافذة بدلاً من ذلك.

لمزيد من المعلومات، راجِع دليل المطوّر لمعاينة الكاميرا وفيديو Your Camera app on different form factors.

الحل 4: تنفيذ إجراءات أساسية للكاميرا باستخدام هدف

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

لمزيد من المعلومات، راجِع مقالة أهداف الكاميرا.

الإعدادات والاستمرارية

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

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

تشمل تغييرات الإعدادات التي يتم تشغيلها بشكلٍ متكرّر screenSize وsmallestScreenSize وscreenLayout وorientation وdensity وfontScale وtouchscreen وkeyboard.

راجِع android:configChanges ومقالة معالجة تغييرات الإعدادات. لمزيد من المعلومات حول إدارة حالة التطبيق، راجِع مقالة حفظ حالات واجهة المستخدم.

تغييرات إعدادات الكثافة

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

إعداد ملف AndroidManifest.xml

  • density: يُعلن عن أنّ التطبيق سيتعامل مع تغيير كثافة الشاشة
  • تغييرات الإعدادات الأخرى: من الجيد أيضًا الإعلان عن تغييرات الإعدادات الأخرى التي تحدث بشكلٍ متكرّر، على سبيل المثال، screenSize وorientation وkeyboardHidden وfontScale وما إلى ذلك

يمنع الإعلان عن الكثافة (وتغييرات الإعدادات الأخرى) النظام من إعادة تشغيل النشاط ويستدعي بدلاً من ذلك الدالة onConfigurationChanged().

تنفيذ الدالة onConfigurationChanged()

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

  • تأكَّد من تغيير النقاط في البوصة إلى newConfig.densityDpi
  • أعِد ضبط طرق العرض المخصّصة والعناصر القابلة للرسم المخصّصة وما إلى ذلك على الكثافة الجديدة

عناصر الموارد التي يجب معالجتها

  • مورد الصورة: استبدِل الصور النقطية والعناصر القابلة للرسم بموارد خاصة بالكثافة ، أو اضبط المقياس مباشرةً
  • وحدة التنسيق (تحويل dp إلى بكسل): أعِد احتساب حجم العرض والهامش، الحشو
  • حجم الخط والنص: أعِد تطبيق حجم النص بوحدة sp
  • رسم View/Canvas مخصّص: عدِّل القيم المستندة إلى البكسل المستخدَمة لـ رسم Canvas

تحديد اتجاه التطبيق

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

الحل 1: استخدام Configuration.orientation

تحدّد هذه السمة الاتجاه الذي يتم عرض تطبيقك به حاليًا.

الحل 2: استخدام WindowMetrics#getBounds()

يمكنك الحصول على حدود العرض الحالية للتطبيق والتحقّق من عرضه وارتفاعه لتحديد الاتجاه.

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

الأوضاع وحالات العرض

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

لتمييز تطبيقك على الأجهزة القابلة للطي التي تتوافق مع HALF_OPENED، استخدِم واجهات برمجة تطبيقات Jetpack WindowManager، مثل FoldingFeature.

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

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

تثبيت الاتجاه على الاتجاه الطبيعي للمستشعر

بالنسبة إلى حالات الاستخدام المحدّدة جدًا، لا سيما التطبيقات التي تحتاج إلى الاستحواذ على الشاشة بأكملها بغض النظر عن حالة طي الجهاز، يتيح لك العَلم 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 التي قد تغيّر سلوك تطبيقك.

لمزيد من المعلومات حول إنشاء تطبيقات متكيّفة، راجِع إرشادات جودة التطبيقات المتكيّفة.