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

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

  1. כדי לאכוף את התצוגה מקצה לקצה ב-Android מגרסה 15 ואילך, צריך לטרגט ל-Android 15 (רמת API‏ 35) ומעלה. האפליקציה מוצגת מאחורי ממשק המשתמש של המערכת. אפשר לשנות את ממשק המשתמש של האפליקציה על ידי טיפול ב-insets.
  2. אופציונלי: קוראים ל-enableEdgeToEdge() ב-Activity.onCreate(), כדי שהאפליקציה תוצג מקצה לקצה בגרסאות קודמות של Android.
  3. מגדירים את android:windowSoftInputMode="adjustResize" ברשומה של AndroidManifest.xml הפעילות. ההגדרה הזו מאפשרת לאפליקציה לקבל את הגודל של מקלדת ה-IME של התוכנה כהזחות פנימיות, וכך לעזור לכם להחיל את הפריסה והריווח המתאימים כשה-IME מופיע ונעלם באפליקציה.

    <!-- In your AndroidManifest.xml file: -->
    <activity
      android:name=".ui.MainActivity"
      android:label="@string/app_name"
      android:windowSoftInputMode="adjustResize"
      android:theme="@style/Theme.MyApplication"
      android:exported="true">
    

שימוש בממשקי ה-API של כתיבה

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

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

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

    enableEdgeToEdge()

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

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

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

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

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

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

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