אחד הכללים של Compose הוא שצריך למדוד את הצאצאים רק פעם אחת. מדידה של הצאצאים פעמיים תגרום להפעלת חריגה בסביבת זמן הריצה. עם זאת, יש מקרים שבהם תצטרכו לספק מידע על הילדים לפני שתוכלו למדוד אותם.
התכונה Intrinsics מאפשרת לשלוח שאילתות לגבי צאצאים לפני שהם נמדדים בפועל.
אפשר לבקש את intrinsicWidth
או את intrinsicHeight
של רכיב ה-Composable:
(min|max)IntrinsicWidth
: בהתאם לרוחב הזה, מהו רוחב ה-minimum/maximum שאפשר לצייר בו את התוכן בצורה תקינה?(min|max)IntrinsicHeight
: בהתאם לגובה הזה, מהו הגובה המינימלי/מקסימלי שבו אפשר לצייר את התוכן בצורה תקינה?
לדוגמה, אם שואלים את minIntrinsicHeight
של Text
עם height
אינסופי, הפונקציה תחזיר את height
של ה-Text
כאילו הטקסט צויר בשורה אחת.
פונקציות פנימיות (intrinsics) בפעולה
נניח שאנחנו רוצים ליצור רכיב מורכב שמוצגים בו שני טקסטים במסך, מופרדים באמצעות קו מפריד, כך:
איך אפשר לעשות את זה? אפשר להשתמש ב-Row
עם שני Text
בתוכו שמתרחבים עד כמה שאפשר, ו-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 ) HorizontalDivider( 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)
מגדיר את הגודל של הצאצאים שלו, כך שהם יהיו בגובה המינימלי שלהם. מכיוון שהיא פונקציה רפרסיבית, היא תבצע שאילתה לגבי Row
וגם לגבי הצאצאים שלו minIntrinsicHeight
.
אם נשתמש בזה בקוד שלנו, הוא יפעל כצפוי:
@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 ) HorizontalDivider( 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") } } }
עם תצוגה מקדימה:
הערך של minIntrinsicHeight
ב-composable של Row
יהיה הערך המקסימלי של minIntrinsicHeight
בבניינים שלו. הערך של minIntrinsicHeight
ברכיב Divider
הוא 0 כי הוא לא תופס מקום אם לא מציינים אילוצים. הערך של minIntrinsicHeight
ברכיב Text
יהיה הערך של הטקסט בהתאם ל-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 פיתוח נייטיב