دعم كثافات وحدات البكسل المختلفة

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

تعرض لك هذه الصفحة كيفية تصميم تطبيقك بحيث يتوافق مع كثافات بكسل مختلفة باستخدام وحدات قياس مستقلة عن الدقة وتوفير موارد صور نقطية بديلة لكل كثافة بكسل.

شاهِد الفيديو التالي للحصول على نظرة عامة حول هذه الأساليب.

لمزيد من المعلومات حول تصميم أصول الرموز، راجع إرشادات رموز التصميم متعدد الأبعاد.

استخدام وحدات بكسل مستقلة الكثافة

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

صورة تعرض مثالَين على جهاز بكثافات مختلفة
الشكل 1: يمكن أن تحتوي شاشتان من الحجم نفسه على عدد مختلف من وحدات البكسل.

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

ضع في الاعتبار الجهازين في الشكل 1. العرض الذي يبلغ عرضه 100 بكسل يظهر بحجم أكبر بكثير على الجهاز على اليسار. تظهر طريقة العرض المحددة بعرض 100 بكسل مستقل الكثافة بنفس الحجم على كلتا الشاشتين.

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

على سبيل المثال، لتحديد التباعد بين طريقتي عرض، استخدم dp:

<Button android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/clickme"
    android:layout_marginTop="20dp" />

عند تحديد حجم النص، استخدِم sp:

<TextView android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="20sp" />

تحويل وحدات بكسل مستقلة الكثافة إلى وحدات بكسل

في بعض الحالات، عليك التعبير عن الأبعاد بالبكسل، ثم تحويلها إلى وحدات بكسل. تتم عملية تحويل وحدات البكسل غير المرتبطة بالكثافة إلى وحدات بكسل الشاشة على النحو التالي:

px = dp * (dpi / 160)

ملاحظة: يجب عدم استخدام ترميز ثابت لهذه المعادلة لحساب وحدات البكسل. بدلاً من ذلك، استخدِم TypedValue.applyDimension()، التي تحوّل العديد من أنواع الأبعاد (dp وsp، وغيرها) إلى وحدات بكسل.

تخيل أن التطبيق الذي يتم التعرف فيه على إيماءة التمرير أو التمرير بعد تحريك إصبع المستخدم بمقدار 16 بكسل على الأقل. على الشاشة الأساسية، يجب أن يتحرك إصبع المستخدم لمسافة 16 pixels / 160 dpi، أي ما يعادل 1/10 بوصة (أو 2.5 ملم)، قبل أن يتم التعرّف على الإيماءة.

على جهاز شاشة عالية الكثافة (240 نقطة لكل بوصة)، يجب أن يتحرك إصبع المستخدم 16 pixels / 240 dpi، ما يساوي 1/15 بوصة (أو 1.7 ملم). المسافة أقصر بكثير، وبالتالي يبدو التطبيق أكثر حساسية للمستخدم.

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

Kotlin

// The gesture threshold expressed in dp
private const val GESTURE_THRESHOLD_DP = 16.0f

private var gestureThreshold: Int = 0

// Convert the dps to pixels, based on density scale
gestureThreshold = TypedValue.applyDimension(
  COMPLEX_UNIT_DIP,
  GESTURE_THRESHOLD_DP + 0.5f,
  resources.displayMetrics).toInt()

// Use gestureThreshold as a distance in pixels...

Java

// The gesture threshold expressed in dp
private final float GESTURE_THRESHOLD_DP = 16.0f;

// Convert the dps to pixels, based on density scale
int gestureThreshold = (int) TypedValue.applyDimension(
  COMPLEX_UNIT_DIP,
  GESTURE_THRESHOLD_DP + 0.5f,
  getResources().getDisplayMetrics());

// Use gestureThreshold as a distance in pixels...

ويحدِّد الحقل DisplayMetrics.density عامل المقياس المستخدَم لتحويل وحدات البكسل غير المرتبطة بالبكسل إلى وحدات البكسل وفقًا لكثافة وحدات البكسل الحالية. على الشاشة المتوسطة الكثافة، يساوي DisplayMetrics.density 1.0، وعلى الشاشة العالية الكثافة يساوي 1.5. وعندما تكون الشاشة عالية الكثافة، يساوي 2.0، وعلى الشاشة المنخفضة الكثافة تساوي 0.75. ويستخدم TypedValue.applyDimension() هذا الشكل لمعرفة عدد وحدات البكسل الفعلي للشاشة الحالية.

استخدام قيم الضبط المُعدَّلة مسبقًا

يمكنك استخدام فئة ViewConfiguration للوصول إلى المسافات والسرعات والأوقات الشائعة التي يستخدمها نظام Android. على سبيل المثال، يمكن الحصول على المسافة بالبكسل التي يستخدمها إطار العمل كحدّ التمرير باستخدام getScaledTouchSlop():

Kotlin

private val GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).scaledTouchSlop

Java

private final int GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).getScaledTouchSlop();

تضمن الطرق في ViewConfiguration التي تبدأ بالبادئة getScaled عرض قيمة بالبكسل التي يتم عرضها بشكل صحيح بغض النظر عن كثافة وحدات البكسل الحالية.

تفضيل الرسومات المتجهة

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

غالبًا ما يتم توفير رسومات المتجهات كملفات SVG (Scalable Vector Graphics)، إلا أنّ Android لا يتيح هذا التنسيق، لذا عليك تحويل ملفات SVG إلى تنسيق متجه قابل للرسم في Android.

يمكنك تحويل رسومات موجّهة يمكن تغيير حجمها (SVG) إلى متّجه قابل للرسم باستخدام Vector Asset Studio في Android Studio على النحو التالي:

  1. في نافذة المشروع، انقر بزر الماوس الأيمن على الدليل res واختَر جديد > مادة عرض المتجه.
  2. اختَر ملف محلي (SVG أو PSD).
  3. حدِّد الملف الذي تريد استيراده وأدخِل أي تعديلات.

    صورة توضح كيفية استيراد رسومات SVG في &quot;استوديو Android&quot;
    الشكل 2: استيراد SVG باستخدام Android Studio.

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

  4. انقر على التالي.

  5. في الشاشة التالية، أكِّد مجموعة المصادر التي تريد إضافة الملف إليها في مشروعك وانقر على إنهاء.

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

    res/
      drawable/
        ic_android_launcher.xml
    

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

توفير صور نقطية بديلة

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

صورة تعرض أحجامًا نسبية للصور النقطية بأحجام كثافة مختلفة
الشكل 3: الأحجام النسبية للصور النقطية في مجموعات البيانات ذات الكثافة المختلفة.

هناك العديد من حِزم الكثافة المتاحة للاستخدام في تطبيقاتك. يصف الجدول 1 مؤهلات التهيئة المختلفة المتاحة وأنواع الشاشات التي تنطبق عليها.

الجدول 1. مؤهِّلات التهيئة لكثافات وحدات بكسل مختلفة.

مؤهِّل الكثافة الوصف
ldpi موارد الشاشات منخفضة الكثافة (ldpi) (حوالي 120 نقطة لكل بوصة)
mdpi موارد الشاشات متوسطة الكثافة (mdpi) (حوالي 160 نقطة لكل بوصة) هذه هي الكثافة القاعدية.
hdpi موارد الشاشات عالية الكثافة (hdpi) (حوالي 240 نقطة لكل بوصة)
xhdpi موارد الشاشات عالية الكثافة (xhdpi) (حوالي 320 نقطة لكل بوصة)
xxhdpi مراجع للشاشات عالية الكثافة (xxhdpi) (حوالي 480 نقطة لكل بوصة)
xxxhdpi الموارد المخصصة لاستخدامات الكثافة الفائقة جدًا (xxxhdpi) (حوالي 640 نقطة لكل بوصة).
nodpi موارد لجميع الكثافات. هذه موارد مستقلة عن الكثافة. لا يقيس النظام الموارد التي تم وضع علامة عليها بهذا المؤهل، بغض النظر عن كثافة الشاشة الحالية.
tvdpi موارد الشاشات في مكان ما بين mdpi وhdpi؛ حوالي 213 نقطة لكل بوصة تقريبًا. ولا تعتبر هذه مجموعة كثافة "أساسية". إنها مخصصة في الغالب لأجهزة التلفزيون، ومعظم التطبيقات لا تحتاج إليها، كما أن توفير موارد mdpi وhdpi كافية لمعظم التطبيقات، ويتولى النظام ضبط هذه الموارد على النحو المناسب. وإذا كنت ترى أنه من الضروري توفير موارد tvdpi، يمكنك حجمها بمعامل 1.33 * mdpi. على سبيل المثال، صورة بحجم 100×100 بكسل لشاشات mdpi هي 133x133 بكسل لـ tvdpi.

لإنشاء صور نقطية بديلة قابلة للرسم لكثافات مختلفة، اتبع نسبة تحجيم 3:4:6:8:12:16 بين الكثافات الأساسية الست. على سبيل المثال، إذا كان لديك صورة نقطية قابلة للرسم بحجم 48x48 بكسل للشاشات المتوسطة الكثافة، فإن الأحجام هي:

  • 36×36 (0.75x) للكثافة المنخفضة (ldpi)
  • 48×48 (خط الأساس 1.0x) للكثافة المتوسطة (mdpi)
  • 72×72 (1.5x) للكثافة العالية (hdpi)
  • 96×96 (2.0x) للكثافة العالية جدًا (xhdpi)
  • 144×144 (3.0x) للكثافة العالية جدًا (xxhdpi)
  • 192×192 (4.0x) للكثافة العالية جدًا جدًا (xxxhdpi)

ضع ملفات الصور التي تم إنشاؤها في الدليل الفرعي المناسب ضمن res/:

res/
  drawable-xxxhdpi/
    awesome_image.png
  drawable-xxhdpi/
    awesome_image.png
  drawable-xhdpi/
    awesome_image.png
  drawable-hdpi/
    awesome_image.png
  drawable-mdpi/
    awesome_image.png

بعد ذلك، عند الإشارة إلى @drawable/awesomeimage، يختار النظام الصورة النقطية المناسبة بناءً على نسبة النقاط لكل بوصة (DPI) في الشاشة. إذا لم تقم بتوفير مورد خاص بالكثافة لهذه الكثافة، فإن النظام يحدد أفضل تطابق ثاني ويضبطه ليناسب الشاشة.

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

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

وضع رموز التطبيقات في أدلة mipmap

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

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

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

res/
  mipmap-xxxhdpi/
    launcher_icon.png
  mipmap-xxhdpi/
    launcher_icon.png
  mipmap-xhdpi/
    launcher_icon.png
  mipmap-hdpi/
    launcher_icon.png
  mipmap-mdpi/
    launcher_icon.png

في المثال السابق لجهاز xxhdpi، يمكنك توفير رمز مشغّل تطبيقات عالي الكثافة في دليل mipmap-xxxhdpi.

للحصول على إرشادات تصميم الرموز، راجِع رموز النظام.

للحصول على المساعدة في إنشاء رموز التطبيقات، يمكنك الاطّلاع على مقالة إنشاء رموز التطبيقات باستخدام "استوديو مواد عرض الصور".

نصائح حول مشاكل الكثافة غير الشائعة

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

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

  1. التوسّع المُسبَق للموارد، مثل الصور النقطية القابلة للرسم

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

    إذا طلبت أبعاد مورد تم قياسه مسبقًا، يعرض النظام قيمًا تمثل الأبعاد بعد التحجيم. على سبيل المثال، يتم تغيير حجم الصورة النقطية المصممة بحجم 50×50 بكسل لشاشة mdpi إلى 75×75 بكسل على شاشة بدقة hdpi (إذا لم يكن هناك مورد بديل للدقة العالية في البوصة)، ويبلغ النظام الحجم على هذا النحو.

    هناك بعض المواقف التي قد لا تريد فيها من Android ضبط أحد الموارد مسبقًا. إنّ أسهل طريقة لتجنُّب التحجيم المسبق هي وضع المورد في دليل موارد باستخدام مؤهِّل الإعداد nodpi. مثلاً:

    res/drawable-nodpi/icon.png

    عندما يستخدم النظام الصورة النقطية icon.png من هذا المجلد، لا يغيّر حجمها بناءً على كثافة الجهاز الحالية.

  2. القياس التلقائي لأبعاد البكسل وإحداثياته

    يمكنك إيقاف تغيير الحجم المسبق للسمات والصور من خلال ضبط android:anyDensity على "false" في البيان أو بشكل آلي لـ Bitmap من خلال ضبط inScaled على "false". في هذه الحالة، يضبط النظام تلقائيًا أي إحداثيات بكسل مطلقة وقيم لأبعاد البكسل في وقت الرسم. ويضمن ذلك ضمان استمرار عرض عناصر الشاشة المحدّدة بوحدات البكسل باستخدام الحجم الفعلي نفسه تقريبًا الذي يمكن عرضه بكثافة وحدة البكسل الأساسية (mdpi). يتعامل النظام مع هذا التحجيم بشفافية مع التطبيق ويُبلغ التطبيق عن أبعاد البكسل المُعدَّلة، بدلاً من أبعاد البكسل الفعلية.

    على سبيل المثال، لنفترض أن الجهاز يحتوي على شاشة WVGA عالية الكثافة، مقاس 480×800 وله نفس حجم شاشة HVGA التقليدية، ولكنه يشغّل تطبيقًا أوقف التدرج المسبق. في هذه الحالة، "يكمن" النظام في التطبيق عندما يطلب البحث عن أبعاد الشاشة ويعرض التقرير 320×533، وهي الترجمة التقريبية لكثافة وحدات البكسل.

    بعد ذلك، عندما يقوم التطبيق بعمليات الرسم، مثل إلغاء صلاحية المستطيل من (10,10) إلى (100، 100)، فإن النظام يحول الإحداثيات عن طريق تغيير حجم المقدار المناسب، ويُلغي فعليًا المنطقة (15,15) إلى (150, 150). قد يتسبب هذا التناقض في حدوث سلوك غير متوقع إذا تلاعب تطبيقك مباشرةً بالصورة النقطية التي تم قياسها، إلا أن ذلك يُعدّ مقايضة معقولة لضمان تحقيق أفضل أداء ممكن للتطبيق. إذا واجهت هذا الموقف، يمكنك الاطّلاع على تحويل وحدات dp إلى وحدات بكسل.

    عادةً، لا يتم إيقاف التحجيم المسبق. أفضل طريقة لدعم الشاشات المتعددة هي اتباع الأساليب الأساسية الموضحة في هذه الصفحة.

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

اختبار على جميع كثافة وحدات البكسل

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

إذا كنت تريد إجراء اختبار على أجهزة مادية ولكنك لا تريد شراء الأجهزة، فيمكنك استخدام مركز الاختبار الافتراضي لمنصة Firebase للوصول إلى الأجهزة في مركز بيانات Google.