إعداد مساحات النافذة

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

التعامل مع عمليات الإدراج باستخدام الحشو أو عناصر تعديل الحجم

على سبيل المثال، هذه هي الطريقة الأساسية لتطبيق الإزاحات على محتوى تطبيقك بالكامل:

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

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

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

يتم تحريك جميع أنواع الحواف الداخلية هذه تلقائيًا باستخدام الرسوم المتحركة الخاصة بمحرّك طرق الإدخال (IME) التي تم نقلها إلى الإصدار 21 من واجهة برمجة التطبيقات. وبالتالي، يتم تحريك جميع التصاميم التي تستخدم هذه الحواف تلقائيًا أيضًا عند تغيير قيم الحواف.

هناك ثلاث طرق للتعامل مع الحواف الداخلية لتعديل تصميمات Composable:

أدوات تعديل المساحة المتروكة

تطبِّق Modifier.windowInsetsPadding(windowInsets: WindowInsets) هوامش النافذة المحدّدة كمسافة بادئة، وتعمل تمامًا مثل Modifier.padding. على سبيل المثال، تطبّق Modifier.windowInsetsPadding(WindowInsets.safeDrawing) هوامش الأمان للرسم كحاشية على جميع الجوانب الأربعة.

تتوفّر أيضًا عدّة طرق مساعدة مدمَجة لأنواع الحواف الداخلية الأكثر شيوعًا. Modifier.safeDrawingPadding() هي إحدى هذه الطرق، وهي تعادل Modifier.windowInsetsPadding(WindowInsets.safeDrawing). تتوفّر معدّلات مشابهة لأنواع الإضافات الأخرى.

معدِّلات حجم الإدراج

تطبِّق المعدِّلات التالية مقدارًا من هوامش النافذة الداخلية من خلال ضبط حجم المكوّن ليكون بحجم الهوامش الداخلية:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

تطبيق جانب البدء من windowInsets كعرض (مثل Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

تطبيق الجانب الأخير من windowInsets كعرض (مثل Modifier.width)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

تطبيق الجانب العلوي من windowInsets كارتفاع (مثل Modifier.height)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

تطبيق الجانب السفلي من windowInsets كارتفاع (مثل Modifier.height)

تكون أدوات التعديل هذه مفيدة بشكل خاص لتحديد حجم Spacer يشغل مساحة الحواف الداخلية:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

الاستهلاك من خلال الدفع بالتقسيط

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

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

نتيجةً لذلك، تعمل أدوات تعديل المساحة المتروكة المتداخلة على تغيير مقدار المساحة المتروكة المطبَّقة على كل عنصر قابل للإنشاء تلقائيًا.

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

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

عند إغلاق محرر أسلوب الإدخال، لا يضيف المعدِّل imePadding() أي مساحة متروكة، لأنّ محرر أسلوب الإدخال ليس له ارتفاع. بما أنّ المعدِّل imePadding() لا يطبّق أي مساحة متروكة، لا يتم استخدام أي مساحات داخلية، وسيكون ارتفاع Spacer هو حجم الجانب السفلي من أشرطة النظام.

عند فتح محرر أسلوب الإدخال، يتم تحريك هوامش محرر أسلوب الإدخال لتتطابق مع حجمه، ويبدأ المعدِّل imePadding() في تطبيق مساحة متروكة سفلية لتغيير حجم LazyColumn عند فتح محرر أسلوب الإدخال. عندما يبدأ المعدِّل imePadding() في تطبيق مساحة الحشو السفلية، يبدأ أيضًا في استهلاك مقدار الحواف الداخلية هذا. لذلك، يبدأ ارتفاع Spacer في الانخفاض، لأنّ جزءًا من المساحة المخصّصة لأشرطة النظام قد تم تطبيقه من خلال المعدِّل imePadding(). عندما يطبّق المعدِّل imePadding() مقدارًا من المساحة المتروكة في الأسفل أكبر من أشرطة النظام، يصبح ارتفاع Spacer صفرًا.

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

الشكل 2. عمود كسول من الحافة إلى الحافة مع TextField.

يتم تحقيق هذا السلوك من خلال التواصل بين جميع معدِّلات windowInsetsPadding، ويمكن التأثير فيه بطريقتين أخريين.

تستهلك السمة Modifier.consumeWindowInsets(insets: WindowInsets) أيضًا مساحات متروكة داخلية بالطريقة نفسها التي تستهلك بها السمة Modifier.windowInsetsPadding، ولكنها لا تطبّق المساحات المتروكة الداخلية المستهلكة كحشو. ويكون ذلك مفيدًا عند استخدامه مع معدِّلات حجم الحواف الداخلية، للإشارة إلى العناصر الفرعية بأنّه تم استهلاك مقدار معيّن من الحواف الداخلية:

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

يتشابه سلوك Modifier.consumeWindowInsets(paddingValues: PaddingValues) إلى حد كبير مع سلوك الإصدار الذي يتضمّن وسيطة WindowInsets، ولكنّه يتطلّب PaddingValues عشوائيًا لاستهلاكه. يكون هذا مفيدًا لإعلام الأطفال عندما يتم توفير مساحة متروكة أو تباعد من خلال آلية أخرى غير معدّلات المساحة المتروكة الداخلية، مثل Modifier.padding عادي أو فواصل بارتفاع ثابت:

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

في الحالات التي تكون فيها حواف النافذة الأولية مطلوبة بدون استهلاك، استخدِم قيم WindowInsets مباشرةً، أو استخدِم WindowInsets.asPaddingValues() لعرض PaddingValues للحواف التي لم تتأثر بالاستهلاك. ومع ذلك، بسبب التحذيرات التالية، يُفضّل استخدام أدوات تعديل المساحة المتروكة الداخلية للنافذة وأدوات تعديل حجم المساحة المتروكة الداخلية للنافذة حيثما أمكن ذلك.

المساحات الداخلية ومراحل Jetpack Compose

تستخدم Compose واجهات برمجة التطبيقات الأساسية في AndroidX لتعديل الحواف الداخلية وإنشاء رسوم متحركة لها، وتستخدم هذه الواجهات واجهات برمجة التطبيقات الأساسية في النظام الأساسي التي تدير الحواف الداخلية. وبسبب سلوك هذه المنصة، ترتبط الحواف الداخلية بعلاقة خاصة مع مراحل Jetpack Compose.

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