Compose के लेआउट में इंट्रिंसिक मेज़रमेंट

Compose का एक नियम यह भी है कि आपको अपने बच्चों का आकलन सिर्फ़ एक बार करना चाहिए; बच्चों को दो बार मापने से रनटाइम अपवाद मिलता है. हालांकि, कई बार ऐसा भी होता है भी नहीं है.

Intrinsics की मदद से, बच्चों को मेज़र करने से पहले ही उनसे क्वेरी करने की सुविधा मिलती है.

किसी कंपोज़ेबल में intrinsicWidth या intrinsicHeight मांगा जा सकता है:

  • (min|max)IntrinsicWidth: इस चौड़ाई को देखते हुए, कम से कम/ज़्यादा से ज़्यादा कितना हो सकता है क्या आप अपने कॉन्टेंट को सही तरह से पेंट कर सकते हैं?
  • (min|max)IntrinsicHeight: इस ऊंचाई को देखते हुए, कम से कम/ज़्यादा से ज़्यादा कितना हो सकता है की ऊंचाई के हिसाब से अपने कॉन्टेंट को सही ढंग से पेंट करने में मदद कर सकते हैं?

उदाहरण के लिए, अगर किसी ऐसे Text का minIntrinsicHeight पूछा जाता है जिसमें अनलिमिटेड height हों, तो यह Text का height वैसा ही दिखाएगा जैसे टेक्स्ट को एक पंक्ति में लिखा गया हो.

Intrinsics का इस्तेमाल

मान लें कि हम एक ऐसा कंपोज़ेबल बनाना चाहते हैं जो स्क्रीन को इस तरह से डिवाइडर से अलग करें:

एक-दूसरे के बगल में मौजूद दो टेक्स्ट एलिमेंट, जिनके बीच वर्टिकल डिवाइडर है

हम यह कैसे कर सकते हैं? हमारे पास दो Text के साथ एक Row हो सकता है, जो इस तरह बड़ा होता है स्क्रीन के बीच में एक 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 की सीमा तय करने के लिए, Text की ऊंचाई का इस्तेमाल नहीं किया जा सकता. हम चाहते हैं कि 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")
        }
    }
}

झलक के साथ:

एक-दूसरे के बगल में मौजूद दो टेक्स्ट एलिमेंट, जिनके बीच वर्टिकल डिवाइडर है

Row कॉम्पोज़ेबल का minIntrinsicHeight, उसके बच्चों का ज़्यादा से ज़्यादा minIntrinsicHeight होगा. Divider एलिमेंट का minIntrinsicHeight 0 होता है, क्योंकि कोई पाबंदी न होने पर यह जगह नहीं लेता. Text minIntrinsicHeight, उस टेक्स्ट का होगा जिसे कोई खास width दिया गया है. इसलिए, Row एलिमेंट का height कंस्ट्रेंट Text में से minIntrinsicHeight. इसके बाद, Divider अपने height को Row की तय की गई height सीमा तक बढ़ा देगा.

आपके कस्टम लेआउट में इनट्रिन्सिक

कस्टम Layout या layout मॉडिफ़ायर बनाते समय, अनुमान के आधार पर इनट्रिन्सिक मेज़रमेंट अपने-आप कैलकुलेट हो जाते हैं. इसलिए, ऐसा हो सकता है कि सभी लेआउट के लिए कैलकुलेशन सही न हों. ये एपीआई, इन डिफ़ॉल्ट वैल्यू को बदलने के विकल्प देते हैं.

अपने पसंद के मुताबिक बनाए गए 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.
}