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