عرض المحتوى بشكل شامل في تطبيقك

تجربة ميزة "الكتابة"
‫Jetpack Compose هي مجموعة أدوات واجهة المستخدم المُقترَحة لنظام التشغيل Android. تعرَّف على كيفية العمل على ملء الشاشة في ميزة "الإنشاء".

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

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

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

الشكل 1. أشرطة النظام بتنسيق من الحافة إلى الحافة

عند تنفيذ تنسيق من الحافة إلى الحافة في تطبيقك، يُرجى مراعاة ما يلي:

  1. تفعيل ميزة "العرض حتى حافة الشاشة"
  2. عالج أيّ تداخلات مرئية.
  3. ننصحك بعرض شاشات تمويهية خلف أشرطة النظام.
مثال على صور خلف شريط الحالة
الشكل 2. مثال على الصور التي تظهر في خلفية شريط الحالة

تفعيل ميزة "العرض حتى حافة الشاشة"

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

لتفعيل ميزة "العرض حتى حافة الشاشة" على إصدارات Android السابقة، اتّبِع الخطوات التالية:

  1. أضِف تبعية لمكتبة androidx.activity في ملف build.gradle لتطبيقك أو وحدتك:

    Kotlin

    dependencies {
        val activity_version = activity_version
        // Java language implementation
        implementation("androidx.activity:activity:$activity_version")
        // Kotlin
        implementation("androidx.activity:activity-ktx:$activity_version")
    }

    رائع

    dependencies {
        def activity_version = activity_version
        // Java language implementation
        implementation 'androidx.activity:activity:$activity_version'
        // Kotlin
        implementation 'androidx.activity:activity-ktx:$activity_version'
    }
  2. استورِد دالة الإضافة enableEdgeToEdge إلى تطبيقك:

يمكنك تفعيل ميزة "العرض حتى حافة الشاشة" يدويًا من خلال الاتصال برقم enableEdgeToEdge في onCreate من Activity. يجب استدعاؤه قبل setContentView.

Kotlin

     override fun onCreate(savedInstanceState: Bundle?) {
       enableEdgeToEdge()
       super.onCreate(savedInstanceState)
       ...
     }
   

Java

     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
       EdgeToEdge.enable(this);
       super.onCreate(savedInstanceState);
       ...
     }
   

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

تُعلن دالة enableEdgeToEdge() تلقائيًا أنّه يجب أن يتم عرض التطبيق من الحافة إلى الحافة، كما تضبط ألوان أشرطة النظام.

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

التعامل مع التداخلات باستخدام الأجزاء المضمّنة

قد يتم عرض بعض طرق عرض تطبيقك خلف أشرطة النظام، كما هو موضّح في الشكل 3.

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

في ما يلي أنواع الأجزاء المضمّنة التي تنطبق على عرض تطبيقك على الشاشة بالكامل:

  • أشرطة النظام المضمّنة: وهي الأنسب للعروض التي يمكن النقر عليها والتي يجب ألا تُحجب بصرياً من خلال أشرطة النظام.

  • Display cutout insets (أجزاء الشاشة المقطوعة): للمناطق التي قد تتضمّن جزءًا مقطوعًا من الشاشة بسبب شكل الجهاز

  • العناصر المضمّنة لإيماءات النظام: لمناطق التنقّل باستخدام الإيماءات التي يستخدمها النظام والتي تحظى بالأولوية على تطبيقك.

أجزاء شريط النظام المضمّنة

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

على سبيل المثال، زر الإجراء العائم (FAB) في الشكل 3 مُخفَّى جزئيًا بواسطة شريط التنقّل:

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

لتجنُّب هذا النوع من التداخل المرئي في وضع الإيماءات أو وضع الأزرار، يمكنك زيادة هوامش العرض باستخدام getInsets(int) مع WindowInsetsCompat.Type.systemBars().

يوضّح مثال الرمز البرمجي التالي كيفية تنفيذ المكوّنات المضمّنة في شريط النظام:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets ->
  val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
  // Apply the insets as a margin to the view. This solution sets
  // only the bottom, left, and right dimensions, but you can apply whichever
  // insets are appropriate to your layout. You can also update the view padding
  // if that's more appropriate.
  v.updateLayoutParams<MarginLayoutParams> {
      leftMargin = insets.left
      bottomMargin = insets.bottom
      rightMargin = insets.right
  }

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> {
  Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
  // Apply the insets as a margin to the view. This solution sets only the
  // bottom, left, and right dimensions, but you can apply whichever insets are
  // appropriate to your layout. You can also update the view padding if that's
  // more appropriate.
  MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
  mlp.leftMargin = insets.left;
  mlp.bottomMargin = insets.bottom;
  mlp.rightMargin = insets.right;
  v.setLayoutParams(mlp);

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

في حال تطبيق هذا الحلّ على المثال المعروض في الشكل 3، لن يؤدي ذلك إلى تداخل مرئي في وضع الزر، كما هو موضّح في الشكل 4:

شريط تنقّل شفاف لا يغطي زر الإجراء الرئيسي
الشكل 4. حلّ مشكلة التداخل المرئي في وضع "الأزرار"

وينطبق الأمر نفسه على وضع التنقّل بالإيماءات، كما هو موضّح في الشكل 5:

من الحافة إلى الحافة مع التنقّل بالإيماءات
الشكل 5. حلّ مشكلة التداخل المرئي في وضع التنقّل بالإيماءات

أجزاء مُدمجة من الصور المعروضة

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

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

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets ->
  val bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
      or WindowInsetsCompat.Type.displayCutout()
  )
  v.updatePadding(
    left = bars.left,
    top = bars.top,
    right = bars.right,
    bottom = bars.bottom,
  )
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> {
  Insets bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
    | WindowInsetsCompat.Type.displayCutout()
  );
  v.setPadding(bars.left, bars.top, bars.right, bars.bottom);
  return WindowInsetsCompat.CONSUMED;
});

حدِّد قيمة WindowInsetsCompat من خلال أخذ القيمة المنطقية أو ل أشرطة النظام وأنواع الفتحات في الشاشة.

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

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

أجزاء الإيماءات في النظام

تمثّل الأجزاء المُدمَجة لإيماءات النظام مناطق النافذة التي تُمنَح فيها إيماءات النظام أولوية على تطبيقك. تظهر هذه المناطق باللون البرتقالي في الشكل 6:

مثال على أماكن إدراج إيماءات النظام
الشكل 6. أجزاء الإيماءات في النظام

مثل الأجزاء المُدمَجة في شريط النظام، يمكنك تجنُّب تداخل الأجزاء المُدمَجة في إيماءات النظام باستخدام getInsets(int) مع WindowInsetsCompat.Type.systemGestures().

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

في نظام التشغيل Android 10 أو الإصدارات الأحدث، تحتوي عناصر الإيماءات المضمّنة للنظام على عنصر مضمّن في أسفل الشاشة لإيماءة الرجوع إلى الصفحة الرئيسية، وعنصر مضمّن على يمين الشاشة وعلى يسارها لإيماءات الرجوع:

مثال على قياسات الإيماءات المضمّنة في النظام
الشكل 7. قياسات موضع إيماءات النظام

يوضّح مثال الرمز البرمجي التالي كيفية تنفيذ المكوّنات المضمّنة لإيماءات النظام:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
    val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.updatePadding(insets.left, insets.top, insets.right, insets.bottom)

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
    Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures());
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.setPadding(insets.left, insets.top, insets.right, insets.bottom);

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

مكوّنات Material

تتعامل العديد من مكوّنات Android Material (com.google.android.material) المستندة إلى المشاهد تلقائيًا مع الأجزاء المضمّنة، بما في ذلك BottomAppBar و BottomNavigationView و NavigationRailView وNavigationView.

ومع ذلك، لا يعالج AppBarLayout العناصر المضمّنة تلقائيًا. أضِف android:fitsSystemWindows="true" لمعالجة العناصر المضمّنة في أعلى الصفحة.

اطّلِع على كيفية التعامل مع الأجزاء المُدمجة باستخدام مكونات Material في أداة Compose.

إرسال البيانات المضمّنة المتوافقة مع الإصدارات القديمة

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

مثال على إرسال إعلانات مضمّنة مكسورة
الشكل 8. مثال على إرسال مربّع إعلان مضمّن معطّل لا يتم إرسال الأجزاء المُدمجة إلى عناصر العرض الشقيقة بعد أن تستهلك مجموعة المشاهد 1 الأجزاء المُدمجة على نظام التشغيل Android 10 (المستوى 29 من واجهة برمجة التطبيقات) والإصدارات الأقدم، ما يؤدي إلى تداخل TextView 2 مع شريط التنقّل في النظام. ومع ذلك، يتم إرسال العناصر المضمّنة إلى المشاهدات الشقيقة على الإصدار 11 من نظام التشغيل Android (المستوى 30 لواجهة برمجة التطبيقات) والإصدارات الأحدث، على النحو المتوقّع.

للتأكّد من إرسال المكوّنات المضمّنة إلى العناصر الشقيقة لجميع إصدارات Android المتوافقة، استخدِم ViewGroupCompat#installCompatInsetsDispatch قبل استخدام المكوّنات المضمّنة، المتوفّرة في AndroidX Core وCore-ktx 1.16.0-alpha01 والإصدارات الأحدث.

Kotlin

// Use the i.d. assigned to your layout's root view, e.g. R.id.main
val rootView = findViewById(R.id.main)
// Call before consuming insets
ViewGroupCompat.installCompatInsetsDispatch(rootView)

Java

// Use the i.d. assigned to your layout's root view, e.g. R.id.main
LinearLayout rootView = findViewById(R.id.main);
// Call before consuming insets
ViewGroupCompat.installCompatInsetsDispatch(rootView);
مثال على إرسال إعلانات مضمّنة ثابتة
الشكل 9. تم إصلاح إرسال المُدخلات بعد استدعاء ViewGroupCompat#installCompatInsetsDispatch.

وضع مجسم

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

Kotlin

val windowInsetsController =
      WindowCompat.getInsetsController(window, window.decorView)

// Hide the system bars.
windowInsetsController.hide(Type.systemBars())

// Show the system bars.
windowInsetsController.show(Type.systemBars())

Java

Window window = getWindow();
WindowInsetsControllerCompat windowInsetsController =
      WindowCompat.getInsetsController(window, window.getDecorView());
if (windowInsetsController == null) {
    return;
  }
// Hide the system bars.
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());

// Show the system bars.
windowInsetsController.show(WindowInsetsCompat.Type.systemBars());

يُرجى الاطّلاع على المقالة إخفاء أشرطة النظام في الوضع الشامل لمزيد من المعلومات حول تنفيذ هذه الميزة.

رموز شريط النظام

يضمن طلب enableEdgeToEdge تعديل ألوان رموز شريط النظام عند تغيير موضوع الجهاز.

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

Kotlin

WindowCompat.getInsetsController(window, window.decorView)
    .isAppearanceLightStatusBars = false

Java

WindowCompat.getInsetsController(window, window.getDecorView())
    .setAppearanceLightStatusBars(false);

حماية شريط النظام

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

لإزالة الحماية التلقائية الشفافة لخلفية التنقّل باستخدام الأزرار الثلاثة، اضبط Window.setNavigationBarContrastEnforced على false.

نصائح أخرى

تأكَّد من أنّ عنصر القائمة الأخير لا يتم حجبه بواسطة أشرطة النظام في RecyclerView أو NestedScrollView من خلال التعامل مع الأجزاء المُدمجة وضبط clipToPadding على false.

يعرض الفيديو التالي جهاز RecyclerView مع إيقاف ميزة "العرض من الحافة إلى الحافة" (على يمين الشاشة) وتفعيلها (على يمين الشاشة):

اطّلِع على مقتطفات الرموز البرمجية في القسم إنشاء قوائم ديناميكية باستخدام RecyclerView للاطّلاع على نموذج رمز.

مصادر إضافية

اطّلِع على المراجع التالية للحصول على مزيد من المعلومات عن WindowInsets واستخدام الحركات للتنقّل وطريقة عمل الأجزاء المضمّنة: