אחד הכללים של Compose הוא שצריך למדוד את הרכיבים פעם אחת בלבד. אם מודדים את הרכיבים פעמיים, נוצרת חריגה בזמן הריצה. עם זאת, יש מקרים שבהם צריך לקבל מידע מסוים על הילדים לפני שמודדים אותם.
התכונה Intrinsics מאפשרת לשלוח שאילתות לגבי נתוני ילדים לפני שהם נמדדים בפועל.
אפשר לבקש מ-Gemini את IntrinsicSize.Min
או את IntrinsicSize.Max
של קומפוזיציה:
-
Modifier.width(IntrinsicSize.Min)
– מה הרוחב המינימלי שנדרש כדי להציג את התוכן בצורה תקינה? Modifier.width(IntrinsicSize.Max)
– מה הרוחב המקסימלי שנדרש כדי להציג את התוכן בצורה תקינה?-
Modifier.height(IntrinsicSize.Min)
– מה הגובה המינימלי שנדרש כדי להציג את התוכן בצורה תקינה? -
Modifier.height(IntrinsicSize.Max)
– מה הגובה המקסימלי שנדרש כדי להציג את התוכן בצורה תקינה?
לדוגמה, אם מבקשים את minIntrinsicHeight
של Text
עם אילוצים אינסופיים של width
בפריסה בהתאמה אישית, הוא מחזיר את height
של Text
עם הטקסט שמוצג בשורה אחת.
פונקציות פנימיות (intrinsics) בפעולה
אפשר ליצור רכיב שאפשר להוסיף לו רכיבים אחרים, שמציג שני טקסטים במסך עם קו מפריד ביניהם:
כדי לעשות את זה, משתמשים ב-Row
עם שני רכיבי Text
composable שממלאים את המקום הפנוי, וברכיב Divider
באמצע. ה-Divider
צריך להיות גבוה כמו Text
הכי גבוה, ודק (width = 1.dp
).
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
האזור Divider
מתרחב למסך מלא, וזה לא מה שרצינו:
זה קורה כי Row
מודד כל ילד בנפרד, ואי אפשר להשתמש בגובה של Text
כדי להגביל את Divider
.
כדי שהתג Divider
ימלא את השטח הפנוי בגובה נתון, משתמשים במגדיר height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
מגדיר את הגובה של רכיבי הצאצא שלו כך שיהיה שווה לגובה המינימלי המובנה שלהם. מכיוון שהמשנה הזה הוא רקורסיבי, הוא שולח שאילתה אל minIntrinsicHeight
של Row
ושל חשבונות הצאצא שלו.
הוספת מקש הצירוף הזה לקוד גורמת לו לפעול כצפוי:
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier.height(IntrinsicSize.Min)) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } } // @Preview @Composable fun TwoTextsPreview() { MaterialTheme { Surface { TwoTexts(text1 = "Hi", text2 = "there") } } }
עם תצוגה מקדימה:
הגובה של Row
נקבע באופן הבא:
- הערך
minIntrinsicHeight
של רכיב ה-Row
הוא המקסימום שלminIntrinsicHeight
של רכיבי הצאצא שלו. - הערך של
minIntrinsicHeight
באלמנטDivider
הוא 0, כי אם לא מציינים אילוצים, האלמנט לא תופס מקום. - ה-
Text
minIntrinsicHeight
הוא של הטקסט עבורwidth
ספציפי. - לכן, המגבלה
height
של הרכיבRow
הופכת למקסימוםminIntrinsicHeight
של הרכיביםText
. -
Divider
מרחיב אתheight
לאילוץheight
שניתן על ידיRow
.
מאפיינים מובנים בפריסות בהתאמה אישית
כשיוצרים משנה מותאם אישית של Layout
או layout
, המערכת מחשבת באופן אוטומטי את המידות הפנימיות על סמך קירובים. לכן, יכול להיות שהחישובים לא יהיו נכונים לכל הפריסות. ממשקי ה-API האלה מציעים אפשרויות לשינוי ברירות המחדל.
כדי לציין את המדידות הפנימיות של Layout
מותאם אישית, צריך לבטל את ברירת המחדל של minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
ו-maxIntrinsicHeight
של ממשק MeasurePolicy
כשיוצרים אותו.
@Composable fun MyCustomComposable( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( content = content, modifier = modifier, measurePolicy = object : MeasurePolicy { override fun MeasureScope.measure( measurables: List<Measurable>, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurables: List<IntrinsicMeasurable>, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
כשיוצרים משנה מותאם אישית של layout
, מבטלים את השיטות הקשורות בממשק LayoutModifier
.
fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
מומלץ
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- פריסות בהתאמה אישית {:#custom-layouts}
- קווי יישור ב-Jetpack פיתוח נייטיב
- שלבים ב-Jetpack פיתוח נייטיב