מדידות מהותיות בפריסות אימייל

אחד מהכללים בניסוח האוטומטי הוא שצריך למדוד את ביצועי הילדים רק פעם אחת. כשמודדים ילדים, זו יכולה להיות חריגת זמן ריצה. אבל יש מקרים שבהם כשצריך מידע על הילדים לפני שהם מודדים אותם.

באמצעות Intrinsics אפשר להריץ שאילתות על ילדים לפני שהם נמדדים בפועל.

כדי ליצור תוכן קומפוזבילי, אפשר לבקש את ה-intrinsicWidth או ה-intrinsicHeight שלו:

  • (min|max)IntrinsicWidth: בהתחשב ברוחב הזה, מהו המינימום/מקסימום האם ניתן לצבוע את התוכן כמו שצריך?
  • (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
        )
        Divider(
            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
        )
        Divider(
            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 מהצאצאים שלה. של הרכיב Divider הערך של minIntrinsicHeight הוא 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.
}