فئات أحجام النوافذ هي مجموعة من نقاط توقّف إطارات العرض التي تساعدك في تصميم وتطوير واختبار التنسيقات السريعة الاستجابة/المتكيّفة. توازن نقاط التوقّف بين بساطة التصميم ومرونة تحسين تطبيقك لحالات الاستخدام الفريدة.
تصنّف فئات حجم النافذة مساحة العرض المتاحة لتطبيقك على النحو التالي: مضغوطة أو متوسطة أو موسّعة أو كبيرة أو كبيرة جدًا. يتم تصنيف العرض والارتفاع المتاحَين بشكل منفصل، لذا يكون لتطبيقك في أي وقت فئتان لحجم النافذة، إحداهما للعرض والأخرى للارتفاع. عادةً، يكون العرض المتاح أكثر أهمية من الارتفاع المتاح بسبب انتشار التمرير العمودي، لذا من المرجّح أن يكون فئة حجم النافذة للعرض أكثر صلة بواجهة المستخدم لتطبيقك.
وكما هو موضّح في الأشكال، تتيح لك نقاط التوقّف مواصلة التفكير في التصاميم من حيث الأجهزة والإعدادات. تمثّل كل نقطة توقّف لفئة الحجم حالة الأغلبية لسيناريوهات الأجهزة النموذجية، ويمكن أن تكون إطارًا مرجعيًا مفيدًا أثناء التفكير في تصميمات التنسيقات المستندة إلى نقاط التوقّف.
| فئة الحجم | نقطة الإيقاف | تمثيل الجهاز |
|---|---|---|
| العرض المضغوط | width < 600dp | 99.96% من الهواتف في الوضع العمودي |
| عرض متوسط | 600dp ≤ العرض < 840dp | 93.73% من الأجهزة اللوحية في الوضع العمودي
معظم الشاشات الداخلية الكبيرة غير المطوية في الوضع الرأسي |
| عرض موسّع | 840dp ≤ العرض < 1200dp | 97.22% من الأجهزة اللوحية في الوضع الأفقي
معظم الشاشات الداخلية الكبيرة غير المطوية في الوضع الأفقي تكون بعرض موسّع على الأقل |
| عرض كبير | 1200dp ≤ العرض < 1600dp | شاشات الأجهزة اللوحية الكبيرة |
| عرض كبير جدًا | width ≥ 1600dp | شاشات الكمبيوتر |
| الارتفاع المكثّف | الارتفاع < 480dp | 99.78% من الهواتف في الوضع الأفقي |
| ارتفاع متوسط | 480dp ≤ الارتفاع < 900dp | 96.56% من الأجهزة اللوحية في الوضع الأفقي
97.59% من الهواتف في الوضع العمودي |
| الارتفاع الموسّع | height ≥ 900dp | 94.25% من الأجهزة اللوحية في الوضع العمودي |
على الرغم من أنّ تصوُّر فئات الحجم على أنّها أجهزة فعلية قد يكون مفيدًا، إلا أنّ فئات حجم النافذة لا يتم تحديدها بشكل صريح من خلال حجم شاشة الجهاز. لا يُفترض استخدام فئات حجم النافذة مع منطق من النوع isTablet. بدلاً من ذلك، يتم تحديد فئات حجم النافذة حسب حجم النافذة المتاح لتطبيقك بغض النظر عن نوع الجهاز الذي يتم تشغيل التطبيق عليه، ما يؤدي إلى نتيجتين مهمتين:
لا تضمن الأجهزة الفعلية توفُّر فئة حجم نافذة معيّنة. يمكن أن تختلف مساحة الشاشة المتاحة لتطبيقك عن حجم شاشة الجهاز لأسباب عديدة. على الأجهزة الجوّالة، يمكن أن يقسّم وضع تقسيم الشاشة الشاشة بين تطبيقَين. على أجهزة ChromeOS، يمكن عرض تطبيقات Android في نوافذ قابلة لتغيير الحجم بشكل عشوائي، مثل نوافذ سطح المكتب. يمكن أن تحتوي الأجهزة القابلة للطي على شاشتين مختلفتَي الحجم يمكن الوصول إليهما بشكل منفصل عن طريق طي الجهاز أو فتحه.
يمكن أن يتغير فئة حجم النافذة طوال فترة استخدام تطبيقك. أثناء تشغيل تطبيقك، يمكن أن يؤدي تغيير اتجاه الجهاز وتنفيذ مهام متعددة وطي الجهاز أو فتحه إلى تغيير مقدار مساحة الشاشة المتاحة. نتيجةً لذلك، يكون فئة حجم النافذة ديناميكية، ويجب أن تتكيّف واجهة مستخدم تطبيقك معها.
تتطابق فئات حجم النافذة مع نقاط التوقّف المضغوطة والمتوسطة والموسّعة في إرشادات التصميم المتعدد الأبعاد. بالإضافة إلى ذلك، تمت إضافة نقاط توقّف كبيرة وكبيرة جدًا لاستهداف أجهزة الكمبيوتر المكتبي والشاشات المتصلة بشكل أفضل.
استخدِم فئات حجم النافذة لاتخاذ قرارات عالية المستوى بشأن تصميم التطبيق، مثل تحديد ما إذا كان سيتم استخدام تصميم أساسي معيّن للاستفادة من مساحة الشاشة الإضافية.
يمكنك حساب القيمة الحالية
WindowSizeClass
باستخدام
WindowSizeClass#compute()
الدالة التي توفرها Jetpack
مكتبة WindowManager. المثال التالي
كيفية حساب فئة حجم النافذة وتلقّي التحديثات عند
تغييرات فئة حجم النافذة:
Kotlin
class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. val container: ViewGroup = binding.container // Add a utility view to the container to hook into // View.onConfigurationChanged(). This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged(), // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged() is // called in those scenarios. container.addView(object : View(this) { override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) computeWindowSizeClasses() } }) computeWindowSizeClasses() } private fun computeWindowSizeClasses() { val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this) val width = metrics.bounds.width() val height = metrics.bounds.height() val density = resources.displayMetrics.density val windowSizeClass = WindowSizeClass.compute(width/density, height/density) // COMPACT, MEDIUM, or EXPANDED val widthWindowSizeClass = windowSizeClass.windowWidthSizeClass // COMPACT, MEDIUM, or EXPANDED val heightWindowSizeClass = windowSizeClass.windowHeightSizeClass // Use widthWindowSizeClass and heightWindowSizeClass. } }
Java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. ViewGroup container = binding.container; // Add a utility view to the container to hook into // View.onConfigurationChanged(). This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged(), // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged() is // called in those scenarios. container.addView(new View(this) { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); computeWindowSizeClasses(); } }); computeWindowSizeClasses(); } private void computeWindowSizeClasses() { WindowMetrics metrics = WindowMetricsCalculator.getOrCreate() .computeCurrentWindowMetrics(this); int width = metrics.getBounds().width(); int height = metrics.getBounds().height(); float density = getResources().getDisplayMetrics().density; WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density); // COMPACT, MEDIUM, or EXPANDED WindowWidthSizeClass widthWindowSizeClass = windowSizeClass.getWindowWidthSizeClass(); // COMPACT, MEDIUM, or EXPANDED WindowHeightSizeClass heightWindowSizeClass = windowSizeClass.getWindowHeightSizeClass(); // Use widthWindowSizeClass and heightWindowSizeClass. } }
فئات حجم نافذة الاختبار
أثناء إجراء تغييرات على التنسيق، اختبِر سلوك التنسيق على جميع أحجام النوافذ، خاصةً عند عرض النقطة الفاصلة في التنسيقات المضغوطة والمتوسطة والموسّعة.
إذا كان لديك تنسيق حالي للشاشات المدمجة، عليك أولاً تحسين التنسيق لفئة الحجم ذات العرض الموسّع، لأنّ فئة الحجم هذه توفّر أكبر مساحة للمحتوى الإضافي وتغييرات واجهة المستخدم. بعد ذلك، حدِّد التصميم الذي يناسب فئة الحجم المتوسطة، وفكِّر في إضافة تصميم متخصص.
الخطوات التالية
لمزيد من المعلومات حول كيفية استخدام فئات حجم النافذة لإنشاء تصميمات متجاوبة/قابلة للتكيّف، راجِع ما يلي:
بالنسبة إلى التنسيقات المستندة إلى Compose: إتاحة أحجام عرض مختلفة
بالنسبة إلى التنسيقات المستندة إلى طرق العرض: التصميم السريع الاستجابة/التكيّفي مع طرق العرض
لمزيد من المعلومات حول ما يجعل التطبيق رائعًا على جميع الأجهزة وأحجام الشاشات، يمكنك الاطّلاع على ما يلي: