ב-Compose, רכיבי ממשק המשתמש מיוצגים על ידי הפונקציות הניתנות ליצירה שמפיקות קטע של ממשק משתמש כשהן מופעלות, ולאחר מכן מתווספות לעץ של ממשק המשתמש שעבר עיבוד (render) במסך. לכל רכיב בממשק המשתמש יש הורה אחד ויכולים להיות לו הרבה צאצאים. כל רכיב נמצא גם בתוך האב שלו, ומוגדר במיקום (x, y) ובגודל, שמוגדר כ-width
ו-height
.
רכיבי ההורה מגדירים את האילוצים של רכיבי הצאצא שלהם. האלמנט מתבקש להגדיר את הגודל שלו במסגרת המגבלות האלה. האילוצים מגבילים את ערכי המינימום והמקסימום width
ו-height
של הרכיב. אם לרכיב יש רכיבי צאצא, הוא עשוי למדוד כל צאצא כדי לקבוע את הגודל שלו. אחרי שרכיב קובע את הגודל שלו ומדווח עליו, יש לו הזדמנות להגדיר איך למקם את רכיבי הצאצא שלו ביחס לעצמו, כפי שמתואר בפירוט במאמר יצירת פריסות בהתאמה אישית.
פריסה של כל צומת בעץ ממשק המשתמש היא תהליך שמורכב משלושה שלבים. כל צומת צריך:
- מדידה של צאצאים
- לקבוע את הגודל שלו
- מיקום הצאצאים שלו
השימוש בהיקפים מגדיר מתי תוכלו למדוד את הילדים ולמקם אותם.
אפשר למדוד פריסה רק במהלך אישורים של מדידה ופריסה, וילד או הילדה יכולים להופיע רק במהלך אישורי הפריסה (ורק אחרי שהם נמדדים). בגלל היקפים של פיתוח הכתיבה, כמו MeasureScope
ו-PlacementScope
, האכיפה הזו נאכפת בזמן הקומפילציה.
שימוש בתכונת השינוי של הפריסה
אפשר להשתמש בתכונת הצירוף layout
כדי לשנות את אופן המדידה והפריסה של הרכיב. Layout
הוא פונקציית lambda. הפרמטרים שלו כוללים את הרכיב שאפשר למדוד, שמוענק כ-measurable
, ואת האילוצים הנכנסים של ה-composable, שמוענק כ-constraints
. כך עשוי להיראות שינוי מותאם אישית של הפריסה:
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
נציג את הסמל Text
במסך ונשלוט במרחק מהחלק העליון ועד לשורת הבסיס של שורת הטקסט הראשונה. זה בדיוק מה שעושה הצירוף paddingFromBaseline
, אנחנו מיישמים אותו כאן כדוגמה.
כדי לעשות זאת, משתמשים במקש המשנה layout
כדי למקם את ה-Composable במסך באופן ידני. זוהי ההתנהגות הרצויה שבה Text
top padding מוגדר 24.dp
:
זה הקוד שיוצר את המרווח הזה:
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) } }
מה קורה בקוד הזה:
- כדי למדוד את הערך של
Text
שמיוצג על ידי הפרמטר המדד, קוראים לפונקציהmeasurable.measure(constraints)
בפרמטר lambdameasurable
. - כדי לציין את הגודל של התוכן הקומפוזבילי באמצעות קריאה ל-method
layout(width, height)
, נותנת גם lambda להצבת הרכיבים העטופים. במקרה הזה, זהו הגובה בין קו הבסיס האחרון לבין המרווח הפנימי העליון שנוסף. - כדי למקם את הרכיבים המגולגלים במסך, קוראים ל-
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)) } }
יצירת פריסות בהתאמה אישית
המשתנה layout
משנה רק את ה-composable הקורא. כדי למדוד ולתכנן את הפריסה של כמה רכיבים מורכבים, צריך להשתמש ברכיב המורכב 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 } } } }
רכיבי ה-Composable הצאצאים מוגבלים על ידי האילוצים של Layout
(ללא האילוצים של minHeight
), והם ממוקמים על סמך yPosition
של ה-Composable הקודם.
כך משתמשים בתוכן הקומפוזבילי בהתאמה אישית:
@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!") } }
כיוון הפריסה
כדי לשנות את כיוון הפריסה של רכיב מורכב, משנים את ההרכב המקומי של LocalLayoutDirection
.
אם מטמיעים תכנים קומפוזביליים באופן ידני במסך, LayoutDirection
הוא חלק מה-LayoutScope
של המגביל layout
או של התוכן הקומפוזבילי Layout
.
כשמשתמשים ב-layoutDirection
, צריך להציב תכנים קומפוזביליים באמצעות place
. בניגוד לשיטה placeRelative
, הערך של place
לא משתנה בהתאם לכיוון של הפריסה (שמאל לימין לעומת ימין לשמאל).
פריסות בהתאמה אישית בפעולה
תוכלו לקרוא מידע נוסף על פריסות ומגבילי התאמה במאמר פריסות בסיסיות בכתיבה, ולקרוא על פריסות בהתאמה אישית בפעולה בקטע כתיבת דוגמאות ליצירת פריסות בהתאמה אישית.
מידע נוסף
למידע נוסף על פריסות בהתאמה אישית ב-Compose, תוכלו לעיין במקורות המידע הנוספים הבאים.
סרטונים
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- מדידות מובנות בפריסות של Compose
- גרפיקה ב-Compose
- הרכבת משתנים