التأكّد من أنّ واجهة المستخدم تعمل مع أجزاء النافذة المُدمجة

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

على سبيل المثال، في ما يلي الطريقة الأساسية لتطبيق المكوّنات المضمّنة على محتوى تطبيقك بالكامل:

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

    enableEdgeToEdge()

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

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

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

هناك طريقتان أساسيتان لاستخدام أنواع الحشو هذه لتعديل تنسيقات العناصر القابلة للتركيب: عناصر تعديل الحشو وعناصر تعديل حجم الحشو.

مُعدِّلات المساحة المتروكة

يطبّق 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
            )
        )
    }
}

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

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

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

الشكل 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) بطريقة مشابهة جدًا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.

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