WindowInsets הוא ממשק ה-API הסטנדרטי ב-Jetpack Compose לטיפול באזורים במסך שמוסתרים באופן חלקי או מלא על ידי ממשק המשתמש של המערכת. האזורים האלה כוללים את שורת הסטטוס, סרגל הניווט והמקלדת הווירטואלית. לחלופין, אפשר להעביר WindowInsetsRulers מוגדר מראש כמו SafeDrawing אל Modifier.fitInside או Modifier.fitOutside כדי ליישר את התוכן עם סרגלי המערכת והחלק החסר במסך, או ליצור WindowInsetsRulers בהתאמה אישית.
היתרונות של WindowInsetsRulers
- הימנעות ממורכבות בצריכה: הוא פועל במהלך שלב המיקום של הפריסה. המשמעות היא שהיא עוקפת לחלוטין את שרשרת הצריכה של השוליים הפנימיים, ותמיד יכולה לספק את המיקומים המוחלטים הנכונים של סרגלי המערכת והחלקים החסרים במסך, בלי קשר לפריסות האב. השימוש בשיטות
Modifier.fitInsideאוModifier.fitOutsideיכול לעזור לפתור בעיות שקשורות לשימוש לא נכון ב-insets ברכיבי Composables ברמת האב. - קל להימנע מסרגלי המערכת: המערכת עוזרת לתוכן באפליקציה להימנע מסרגלי המערכת ומחלקים חתוכים בתצוגה, והיא יכולה להיות פשוטה יותר לשימוש מאשר
WindowInsetsישירות. - ניתן להתאמה אישית מלאה: מפתחים יכולים ליישר תוכן לסרגלים מותאמים אישית, ולקבל שליטה מדויקת בפריסות שלהם באמצעות פריסות מותאמות אישית.
חסרונות של WindowInsetsRulers
- אי אפשר להשתמש בו למדידה: מכיוון שהוא פועל במהלך שלב המיקום, פרטי המיקום שהוא מספק לא זמינים במהלך שלב המדידה הקודם.
התאמת התוכן לשיטות של מקשי צירוף
Modifier.fitInside מאפשר לאפליקציות ליישר תוכן לסרגלי המערכת ולחלקים החסרים במסך. אפשר להשתמש בו במקום ב-WindowInsets. הפונקציה Modifier.fitOutside היא בדרך כלל ההיפוך של Modifier.fitInside.
לדוגמה, כדי לוודא שהתוכן באפליקציה לא חופף לסרגלי המערכת ולחלק החסר במסך, אפשר להשתמש ב-fitInside(WindowInsetsRulers.safeDrawing.current).
@Composable fun FitInsideDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc... .fitInside(WindowInsetsRulers.SafeDrawing.current) ) }
בטבלה הבאה מוצג איך התוכן באפליקציה ייראה עם סרגלים מוגדרים מראש עם Modifier.fitInside או Modifier.fitOutside.
| סוג סרגל מוגדר מראש | ||
|---|---|---|
![]() |
![]() |
|
![]() |
לא רלוונטי |
|
![]() |
![]() |
|
![]() |
לא רלוונטי (במקומו יש להשתמש ב- |
|
![]() |
![]() |
כדי להשתמש ב-Modifier.fitInside וב-Modifier.fitOutside, צריך להגביל את הפונקציות הניתנות להרכבה. כלומר, צריך להגדיר מגבירים כמו Modifier.size או Modifier.fillMaxSize.
חלק מהכללים, כמו Modifier.fitOutside ב-SafeDrawing ו-SystemBars, מחזירים כמה כללים. במקרה כזה, מערכת Android ממקמת את רכיב ה-Composable באמצעות סרגל אחד משמאל, מלמעלה, מימין ומלמטה.
איך להימנע מ-IME באמצעות Modifier.fitInside
כדי לטפל באלמנטים התחתונים באמצעות IME עם Modifier.fitInside, מעבירים RectRuler שמקבל את הערך הפנימי ביותר של NavigationBar ושל Ime.
@Composable fun FitInsideWithImeDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.NavigationBars.current, WindowInsetsRulers.Ime.current ) ) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier.align(Alignment.BottomStart).fillMaxWidth() ) } }
הימנעו משורת הסטטוס ומשורת הכותרת באמצעות Modifier.fitInside
באופן דומה, כדי לוודא שהאלמנטים העליונים לא חופפים את שורת הסטטוס ואת שורת הכותרת, צריך להעביר את Modifier.fitInsider עם RectRuler שמקבל את הערך הפנימי ביותר של StatusBars ושל CaptionBar.
@Composable fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.StatusBars.current, WindowInsetsRulers.CaptionBar.current ) ) ) }
יצירת WindowInsetsRulers בהתאמה אישית
אפשר ליישר את התוכן לסרגלים מותאמים אישית. לדוגמה, נניח שיש קומפוזיציה של הורה שבה הטיפול ב-insets לא תקין, וזה גורם לבעיות ריווח בקומפוזיציית צאצא. אפשר לפתור את הבעיה הזו בדרכים אחרות, כולל באמצעות Modifier.fitInside, אבל אפשר גם ליצור סרגל מותאם אישית כדי ליישר במדויק את רכיב ה-Composable של הצאצא בלי לתקן את הבעיה ברכיב האב במעלה הזרם, כמו שמוצג בדוגמה ובסרטון הבאים:
@Composable fun WindowInsetsRulersDemo(modifier: Modifier) { Box( contentAlignment = BottomCenter, modifier = modifier .fillMaxSize() // The mistake that causes issues downstream, as .padding doesn't consume insets. // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars), // assume it's difficult to identify this issue to see how WindowInsetsRulers can help. .padding(WindowInsets.navigationBars.asPaddingValues()) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child // Composable without having to fix the parent upstream. .alignToSafeDrawing() // .imePadding() // .fillMaxWidth() ) } } fun Modifier.alignToSafeDrawing(): Modifier { return layout { measurable, constraints -> if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) { val placeable = measurable.measure(constraints) val width = placeable.width val height = placeable.height layout(width, height) { val bottom = WindowInsetsRulers.SafeDrawing.current.bottom .current(0f).roundToInt() - height val right = WindowInsetsRulers.SafeDrawing.current.right .current(0f).roundToInt() val left = WindowInsetsRulers.SafeDrawing.current.left .current(0f).roundToInt() measurable.measure(Constraints.fixed(right - left, height)) .place(left, bottom) } } else { val placeable = measurable.measure(constraints) layout(placeable.width, placeable.height) { placeable.place(0, 0) } } } }
בסרטון הבא מוצגת דוגמה לשימוש ב-IME שגורם לבעיה בהזחת הטקסט, שנובעת מפריט אב במיקום גבוה יותר בתמונה שמוצגת בצד ימין. כדי לפתור את הבעיה, נעשה שימוש בסרגלים מותאמים אישית בתמונה שמוצגת בצד שמאל. ריווח נוסף מוצג מתחת ל-TextField
Composable כי הריווח של סרגל הניווט לא נוצל על ידי רכיב ההורה. הילד ממוקם במיקום הנכון בתמונה השמאלית באמצעות סרגל מותאם אישית, כפי שניתן לראות בדוגמת הקוד הקודמת.
אימות ההגבלות על ההורים
כדי להשתמש בWindowInsetsRulers בצורה בטוחה, חשוב לוודא שההורה מספק אילוצים תקפים. צריך להגדיר גודל לתגי הורה, והם לא יכולים להסתמך על הגודל של תג צאצא שמשתמש במאפיין WindowInsetsRulers. שימוש ב-fillMaxSize או במגדירי גודל אחרים
בפונקציות Composables של ההורה.
באופן דומה, הצבת רכיב שאפשר להרכיב ממנו ממשק משתמש שמשתמש ב-WindowInsetsRulers בתוך מאגר גלילה כמו verticalScroll עלולה לגרום להתנהגות לא צפויה, כי מאגר הגלילה מספק אילוצי גובה בלתי מוגבלים, שלא תואמים ללוגיקה של הסרגל.







