WindowInsets
הוא ממשק ה-API הסטנדרטי ב-Jetpack Compose לטיפול באזורים במסך שמוסתרים באופן חלקי או מלא על ידי ממשק המשתמש של המערכת. האזורים האלה כוללים את שורת הסטטוס, סרגל הניווט והמקלדת הווירטואלית. אפשר גם להעביר WindowInsetsRulers
מוגדר מראש כמו SafeDrawing
אל Modifier.fitInside
או Modifier.fitOutside
כדי ליישר את התוכן עם סרגלי המערכת והחלק החסר במסך, או ליצור WindowInsetsRulers
בהתאמה אישית.
היתרונות של WindowInsetsRulers
- הימנעות ממורכבות בצריכה: הוא פועל במהלך שלב המיקום של הפריסה. המשמעות היא שהיא עוקפת לחלוטין את שרשרת הצריכה של השוליים הפנימיים, ותמיד יכולה לספק את המיקומים המוחלטים הנכונים של סרגלי המערכת והחלקים החסרים במסך, בלי קשר לפריסות האב. השימוש בשיטות
Modifier.fitInside
אוModifier.fitOutside
יכול לעזור לפתור בעיות שקשורות לשימוש שגוי ב-insets ברכיבי Composables של צאצאים. - קל להימנע מסרגלי המערכת: הממשק עוזר לתוכן באפליקציה להימנע מסרגלי המערכת ומחלקים חתוכים במסך, והוא יכול להיות פשוט יותר לשימוש מאשר שימוש ישיר ב-
WindowInsets
. - ניתן להתאמה אישית מלאה: מפתחים יכולים ליישר תוכן לסרגלים מותאמים אישית, ולקבל שליטה מדויקת בפריסות שלהם באמצעות פריסות מותאמות אישית.
החסרונות של WindowInsetsRulers
- אי אפשר להשתמש בו למדידה: מכיוון שהוא פועל במהלך שלב המיקום, פרטי המיקום שהוא מספק לא זמינים במהלך שלב המדידה הקודם.
- פוטנציאל לחוסר יציבות של פריסת הרכיבים: יכול להיות שייגרמו קריסות אם הגודל של פריסת רכיבים ברמת ההורה תלוי בגודל של רכיבי הצאצא. מכיוון שילד שמשתמש ב-
WindowInsetsRulers
עשוי לשנות את המיקום או הגודל שלו במהלך המיקום, הוא יכול ליצור מחזור פריסה לא יציב.
יצירת WindowInsetsRulers
בהתאמה אישית
אפשר ליישר את התוכן לסרגלים מותאמים אישית. לדוגמה, נניח שיש תוכן קומפוזבילי הורה שמטפל בצורה לא תקינה בשוליים הפנימיים, וזה גורם לבעיות בריווח בתוכן קומפוזבילי צאצא. אפשר לפתור את הבעיה הזו בדרכים אחרות, כולל באמצעות Modifier.fitInside
, אבל אפשר גם ליצור סרגל מותאם אישית כדי ליישר במדויק את רכיב ה-Composable של הצאצא בלי לתקן את הבעיה ברכיב ה-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
או במגדירי גודל אחרים בקומפוזיציות הורה.
באופן דומה, הצבת רכיב שאפשר להוסיף לו רכיבים אחרים שמשתמש ב-WindowInsetsRulers
בתוך מאגר שאפשר לגלול בו כמו verticalScroll
עלולה לגרום להתנהגות לא צפויה, כי מאגר הגלילה מספק אילוצי גובה בלתי מוגבלים, שלא תואמים ללוגיקה של הסרגל.