ב-Compose, רכיבי ממשק המשתמש מיוצגים על ידי פונקציות קומפוזביליות שפולטות קטע של ממשק משתמש כשהן מופעלות, ואז הן מתווספות לעץ של ממשק המשתמש שמעובד במסך. לכל רכיב בממשק המשתמש יש הורה אחד, ויכולים להיות לו צאצאים רבים. כל רכיב ממוקם גם בתוך רכיב האב שלו, ומצוין כמיקום (x, y) וכגודל, שמצוין כ-width ו-height.
ההורים מגדירים את המגבלות עבור רכיבי הילדים. האלמנט מתבקש להגדיר את הגודל שלו במסגרת המגבלות האלה. האילוצים מגבילים את המינימום והמקסימום של width ושל height של רכיב. אם לרכיב יש רכיבי צאצא, יכול להיות שהוא ימדוד כל אחד מהם כדי לקבוע את הגודל שלו. אחרי שרכיב קובע את הגודל שלו ומדווח עליו, הוא יכול להגדיר איך למקם את רכיבי הצאצא שלו ביחס לעצמו, כמו שמתואר בפירוט במאמר בנושא יצירת פריסות בהתאמה אישית.
הצגת כל צומת בעץ ממשק המשתמש היא תהליך שכולל שלושה שלבים. כל צומת צריך:
- מדידת ילדים
- הגודל נקבע באופן אוטומטי
- מיקום הילדים שלו
השימוש בהיקפים מגדיר מתי אפשר למדוד את הילדים ולמקם אותם.
אפשר למדוד פריסה רק במהלך שלבי המדידה והפריסה, ואפשר למקם רכיב צאצא רק במהלך שלבי הפריסה (ורק אחרי שהוא נמדד). בגלל היקפי ההרכבה כמו MeasureScope ו-PlacementScope, האכיפה מתבצעת בזמן ההידור.
שימוש במקש לשינוי הפריסה
אפשר להשתמש במאפיין layout כדי לשנות את האופן שבו מודדים ומסדרים רכיב. Layout הוא ביטוי למדא; הפרמטרים שלו כוללים את הרכיב שאפשר למדוד, שמועבר כ-measurable, ואת האילוצים הנכנסים של הרכיב הניתן להרכבה, שמועברים כ-constraints. כך יכול להיראות משנה פריסה מותאם אישית:
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
מציגים Text על המסך ושולטים במרחק מהחלק העליון לקו הבסיס של השורה הראשונה של הטקסט. זה בדיוק מה שעושה המשנה paddingFromBaseline. כאן אתם מטמיעים אותו כדוגמה.
כדי לעשות את זה, משתמשים במעבד layout כדי למקם את הרכיב הקומפוזבילי במסך באופן ידני. כך נראית ההתנהגות שמתקבלת כשמגדירים את Text top padding לערך 24.dp:
paddingFromBaseline.
הנה הקוד ליצירת הרווח הזה:
fun Modifier.firstBaselineToTop( firstBaselineToTop: Dp ) = layout { measurable, constraints -> // Measure the composable val placeable = measurable.measure(constraints) // Check the composable has a first baseline check(placeable[FirstBaseline] != AlignmentLine.Unspecified) val firstBaseline = placeable[FirstBaseline] // Height of the composable with padding - first baseline val placeableY = firstBaselineToTop.roundToPx() - firstBaseline val height = placeable.height + placeableY layout(placeable.width, height) { // Where the composable gets placed placeable.placeRelative(0, placeableY) } }
הסבר על הקוד:
- בפרמטר
measurablelambda, מודדים אתTextשמיוצג על ידי הפרמטר שאפשר למדוד באמצעות קריאה ל-measurable.measure(constraints). - כדי לציין את הגודל של הקומפוזבל, קוראים למתודה
layout(width, height), שמחזירה גם למבדא שמשמש למיקום האלמנטים העטופים. במקרה הזה, זה הגובה בין קו הבסיס האחרון לבין המרווח הפנימי העליון שנוסף. - כדי למקם את הרכיבים העטופים במסך, קוראים ל-
placeable.place(x, y). אם לא מציבים את הרכיבים העוטפים, הם לא יוצגו. המיקוםyמתאים לריווח העליון: המיקום של קו הבסיס הראשון של הטקסט.
כדי לוודא שהשינוי פועל כמו שצריך, משתמשים במקש הצירוף הזה ב-Text:
@Preview @Composable fun TextWithPaddingToBaselinePreview() { MyApplicationTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } } @Preview @Composable fun TextWithNormalPaddingPreview() { MyApplicationTheme { Text("Hi there!", Modifier.padding(top = 32.dp)) } }
Text ומוצג בתצוגה מקדימה.
יצירת פריסות בהתאמה אישית
המשנה layout משנה רק את הקומפוזיציה של השיחה. כדי למדוד ולסדר כמה קומפוזבלים, משתמשים במקום זאת בקומפוזבל Layout. קומפוזיציה שאפשר להשתמש בה כדי למדוד ולסדר את הרכיבים הצאצאים באופן ידני. כל הפריסות ברמה גבוהה יותר, כמו Column ו-Row, מבוססות על הקומפוזיציה Layout.
בדוגמה הזו אנחנו יוצרים גרסה בסיסית מאוד של Column. רוב הפריסות בהתאמה אישית פועלות לפי התבנית הזו:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // measure and position children given constraints logic here // ... } }
בדומה לשינוי layout, measurables היא רשימת הילדים שצריך למדוד ו-constraints הן המגבלות של ההורה.
באופן דומה, אפשר להטמיע את MyBasicColumn כך:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // Don't constrain child views further, measure them with given constraints // List of measured children val placeables = measurables.map { measurable -> // Measure each children measurable.measure(constraints) } // Set the size of the layout as big as it can layout(constraints.maxWidth, constraints.maxHeight) { // Track the y co-ord we have placed children up to var yPosition = 0 // Place children in the parent layout placeables.forEach { placeable -> // Position item on the screen placeable.placeRelative(x = 0, y = yPosition) // Record the y co-ord placed up to yPosition += placeable.height } } } }
הקומפוזיציות של הצאצא מוגבלות על ידי האילוצים של Layout (בלי האילוצים של minHeight), והן ממוקמות על סמך yPosition של הקומפוזיציה הקודמת.
כך משתמשים ברכיב הניתן להרכבה בהתאמה אישית:
@Composable fun CallingComposable(modifier: Modifier = Modifier) { MyBasicColumn(modifier.padding(8.dp)) { Text("MyBasicColumn") Text("places items") Text("vertically.") Text("We've done it by hand!") } }
Column.
כיוון הפריסה
כדי לשנות את כיוון הפריסה של רכיב שאפשר להרכיב, משנים את המקומי של ההרכב LocalLayoutDirection.
אם מציבים קומפוזבילים במסך באופן ידני, LayoutDirection הוא חלק מ-LayoutScope של משנה layout או קומפוזביל Layout.
כשמשתמשים ב-layoutDirection, ממקמים את רכיבי ה-Composable באמצעות place. בניגוד ל-method placeRelative, place לא משתנה בהתאם לכיוון הפריסה (משמאל לימין או מימין לשמאל).
פריסות בהתאמה אישית בפעולה
במאמרים פריסות בסיסיות בכתיבה ודוגמאות לכתיבה שיוצרות פריסות בהתאמה אישית אפשר לקרוא מידע נוסף על פריסות ועל שינויים.
מידע נוסף
מידע נוסף על פריסות בהתאמה אישית בכלי הכתיבה זמין במקורות המידע הבאים.
סרטונים
מומלץ בשבילכם
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- מדידות פנימיות בפריסות של Compose
- גרפיקה ב-Compose
- הרכבת מגבילים