הגדרת חלונות מוטמעים

אחרי שהפעילות שלכם השתלטה על הטיפול בכל השוליים הפנימיים, תוכלו להשתמש בממשקי API של Compose כדי לוודא שהתוכן לא מוסתר ושהאלמנטים האינטראקטיביים לא חופפים ל-UI של המערכת. ממשקי ה-API האלה מסנכרנים גם את הפריסה של האפליקציה עם שינויים ב-inset.

טיפול בתוספות באמצעות מאפייני ריפוד או שינוי גודל

לדוגמה, זו השיטה הבסיסית ביותר להחלת השוליים הפנימיים על התוכן של כל האפליקציה:

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

    enableEdgeToEdge()

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

קטע הקוד הזה מחיל את שולי החלון safeDrawing כריווח פנימי מסביב לכל התוכן של האפליקציה. אמנם זה מבטיח שרכיבים שאפשר לקיים איתם אינטראקציה לא יחפפו את ממשק המשתמש של המערכת, אבל זה גם אומר שאף חלק מהאפליקציה לא יוצג מאחורי ממשק המשתמש של המערכת כדי ליצור אפקט מקצה לקצה. כדי להשתמש בכל החלון, צריך לכוונן את המיקום של השוליים הפנימיים במסך או ברכיב.

כל סוגי החלונות הקטנים האלה מונפשים אוטומטית באמצעות אנימציות של IME שהועברו לאחור ל-API 21. כתוצאה מכך, גם כל הפריסות שמשתמשות בערכי השוליים האלה מונפשות באופן אוטומטי כשהערכים משתנים.

יש שלוש דרכים לטפל ב-insets כדי להתאים את פריסות ה-Composable:

ערכים לשינוי מרווחים פנימיים

Modifier.windowInsetsPadding(windowInsets: WindowInsets) מחיל את השוליים הפנימיים של החלון שצוינו כריפוד, בדיוק כמו ש-Modifier.padding היה עושה. לדוגמה, Modifier.windowInsetsPadding(WindowInsets.safeDrawing) מוסיף את השוליים הפנימיים של האזור הבטוח לציור כריפוד בכל 4 הצדדים.

יש גם כמה שיטות מובנות לשימוש בסוגי השוליים הפנימיים הנפוצים ביותר. ‫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) צורכים באופן אוטומטי את החלק של השוליים הפנימיים שמוגדרים כשוליים פנימיים. כשמתעמקים יותר בעץ הקומפוזיציה, מגבירי הריווח הפנימי (padding) של הריווח הפנימי (inset) ומגבירי הגודל של הריווח הפנימי (inset) יודעים שחלק מהריווח הפנימי (inset) כבר נוצל על ידי מגבירי הריווח הפנימי (padding) החיצוניים, ולכן הם לא משתמשים באותו חלק של הריווח הפנימי (inset) יותר מפעם אחת, כדי שלא יהיה יותר מדי רווח נוסף.

בנוסף, אם כבר נעשה שימוש בחלקים של שוליים פנימיים, שינויי הגודל של השוליים הפנימיים לא ישתמשו באותו חלק יותר מפעם אחת. עם זאת, מכיוון שהם משנים את הגודל שלהם ישירות, הם לא צורכים את המרווחים הפנימיים עצמם.

כתוצאה מכך, שינויים במאפייני הריווח של רכיבים מוטמעים משנים אוטומטית את כמות הריווח שמוחלת על כל רכיב שאפשר להרכיב.

אם נסתכל על אותה דוגמה של 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() כדי להחיל ריווח פנימי תחתון, המערכת מתחילה להשתמש גם בכמות הזו של שוליים פנימיים. לכן, הגובה של Spacer מתחיל לרדת, כי המרווח של סרגלי המערכת כבר הוחל על ידי משנה המאפיינים imePadding(). אם משתמשים במגדיר imePadding() כדי להחיל ריווח פנימי תחתון שגדול יותר מסרגלי המערכת, הגובה של Spacer יהיה אפס.

כשמקלדת ה-IME נסגרת, השינויים מתרחשים בסדר הפוך: Spacer מתחיל להתרחב מגובה אפס ברגע שimePadding() מוחל על פחות מהצד התחתון של סרגלי המערכת, עד שבסופו של דבר Spacer תואם לגובה של הצד התחתון של סרגלי המערכת ברגע שמקלדת ה-IME מסיימת את האנימציה שלה.

איור 2. עמודה עצלה מקצה לקצה עם TextField.

ההתנהגות הזו מתאפשרת באמצעות תקשורת בין כל משני windowInsetsPadding, ויש עוד כמה דרכים להשפיע עליה.

Modifier.consumeWindowInsets(insets: WindowInsets) גם צורך מרווחים פנימיים, כמו Modifier.windowInsetsPadding, אבל הוא לא משתמש במרווחים הפנימיים שנצרכו כמרווחים פנימיים. השימוש הזה שימושי בשילוב עם משני הגודל inset, כדי לציין לאחים שחלק מסוים מהשוליים הפנימיים כבר נוצל:

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 משתמש ב-API הבסיסי של AndroidX כדי לעדכן ולהנפיש את השוליים הפנימיים, שמשתמשים ב-API הבסיסי של הפלטפורמה לניהול השוליים הפנימיים. בגלל אופן הפעולה של הפלטפורמה, יש קשר מיוחד בין המרווחים הפנימיים לבין השלבים של Jetpack Compose.

הערך של insets מתעדכן אחרי שלב הקומפוזיציה, אבל לפני שלב הפריסה. כלומר, כשקוראים את הערך של המרווחים הפנימיים בהרכבה, בדרך כלל משתמשים בערך של המרווחים הפנימיים שמאחר בפְרֵים אחד. המשנים המובנים שמתוארים בדף הזה נועדו לדחות את השימוש בערכי השוליים עד לשלב הפריסה, כדי להבטיח שהשימוש בערכי השוליים יתבצע באותו פריים שבו הם מתעדכנים.