कस्टम लेआउट

Compose में, यूज़र इंटरफ़ेस (यूआई) एलिमेंट को कंपोज़ेबल फ़ंक्शन के ज़रिए दिखाया जाता है. ये फ़ंक्शन, कॉल किए जाने पर यूज़र इंटरफ़ेस (यूआई) का एक हिस्सा दिखाते हैं. इसके बाद, इसे यूज़र इंटरफ़ेस (यूआई) ट्री में जोड़ा जाता है, जिसे स्क्रीन पर रेंडर किया जाता है. हर यूज़र इंटरफ़ेस (यूआई) एलिमेंट का एक पैरंट होता है और कई चाइल्ड हो सकते हैं. हर एलिमेंट, अपने पैरंट के अंदर भी मौजूद होता है. इसे (x, y) पोज़िशन और साइज़ के तौर पर बताया जाता है. साइज़ को width और height के तौर पर बताया जाता है.

पैरंट, अपने चाइल्ड एलिमेंट के लिए कंस्ट्रेंट तय करते हैं. किसी एलिमेंट से, उन कंस्ट्रेंट के अंदर अपना साइज़ तय करने के लिए कहा जाता है. कंस्ट्रेंट, किसी एलिमेंट की कम से कम और ज़्यादा से ज़्यादा width और height को सीमित करते हैं. अगर किसी एलिमेंट के चाइल्ड एलिमेंट हैं, तो वह हर चाइल्ड का साइज़ मेज़र करके अपना साइज़ तय कर सकता है. जब कोई एलिमेंट अपना साइज़ तय करके उसकी जानकारी देता है, तो उसके पास यह तय करने का विकल्प होता है कि अपने चाइल्ड एलिमेंट को अपने हिसाब से कैसे प्लेस करना है. इसके बारे में, कस्टम लेआउट बनाना लेख में ज़्यादा जानकारी दी गई है.

यूज़र इंटरफ़ेस (यूआई) ट्री में हर नोड को लेआउट करने की प्रोसेस में तीन चरण होते हैं. हर नोड को ये काम करने होंगे:

  1. अपने सभी चाइल्ड एलिमेंट का साइज़ मेज़र करना
  2. अपना साइज़ तय करना
  3. अपने चाइल्ड एलिमेंट को प्लेस करना
नोड लेआउट के तीन चरण: चाइल्ड नोड का साइज़ मेज़र करना, साइज़ तय करना, और चाइल्ड नोड को जगह पर रखना
इमेज 1. नोड लेआउट के तीन चरण हैं: चाइल्ड एलिमेंट का साइज़ मेज़र करना, साइज़ तय करना, और चाइल्ड एलिमेंट को प्लेस करना.

स्कोप का इस्तेमाल करने से यह तय होता है कि अपने चाइल्ड एलिमेंट को कब मेज़र और प्लेस किया जा सकता है. लेआउट को सिर्फ़ मेज़रमेंट और लेआउट पास के दौरान मेज़र किया जा सकता है. साथ ही, किसी चाइल्ड को सिर्फ़ लेआउट पास के दौरान प्लेस किया जा सकता है. हालांकि, ऐसा सिर्फ़ तब किया जा सकता है, जब उसका साइज़ मेज़र कर लिया गया हो. Compose के स्कोप की वजह से, जैसे कि MeasureScope, और PlacementScope, इसे कंपाइल टाइम पर लागू किया जाता है.

लेआउट मॉडिफ़ायर का इस्तेमाल करना

किसी एलिमेंट को मेज़र और लेआउट करने के तरीके में बदलाव करने के लिए, layout मॉडिफ़ायर का इस्तेमाल किया जा सकता है. Layout एक लैम्डा है. इसके पैरामीटर में, वह एलिमेंट शामिल होता है जिसे मेज़र किया जा सकता है. इसे measurable के तौर पर पास किया जाता है. साथ ही, उस कंपोज़ेबल के आने वाले कंस्ट्रेंट को constraints के तौर पर पास किया जाता है. कस्टम लेआउट मॉडिफ़ायर ऐसा दिख सकता है:

fun Modifier.customLayoutModifier() =
    layout { measurable, constraints ->
        // ...
    }

स्क्रीन पर Text दिखाएं और टेक्स्ट की पहली लाइन की बेसलाइन से ऊपर तक की दूरी को कंट्रोल करें. paddingFromBaseline मॉडिफ़ायर ठीक यही काम करता है. यहां इसे उदाहरण के तौर पर लागू किया जा रहा है. ऐसा करने के लिए, कंपोज़ेबल को स्क्रीन पर मैन्युअल तरीके से प्लेस करने के लिए, layout मॉडिफ़ायर का इस्तेमाल करें. यहां, Text के टॉप पैडिंग को 24.dp पर सेट करने के बाद, दिखने वाला नतीजा दिखाया गया है:

इस इमेज में, यूज़र इंटरफ़ेस (यूआई) के सामान्य पैडिंग और टेक्स्ट पैडिंग के बीच का अंतर दिखाया गया है. यूज़र इंटरफ़ेस (यूआई) की सामान्य पैडिंग से, एलिमेंट के बीच का स्पेस सेट किया जाता है. वहीं, टेक्स्ट पैडिंग से एक बेसलाइन से दूसरी बेसलाइन के बीच का स्पेस सेट किया जाता है
इमेज 2. paddingFromBaseline लागू किया गया टेक्स्ट.

यहां वह कोड दिया गया है जिससे यह स्पेसिंग मिलती है:

fun Modifier.firstBaselineToTop(
    firstBaselineToTop: Dp
) = layout { measurable, constraints ->
    // Measure the composable
    val placeable = measurable.measure(constraints)

    // Check the composable has a first baseline
    check(placeable[FirstBaseline] != AlignmentLine.Unspecified)
    val firstBaseline = placeable[FirstBaseline]

    // Height of the composable with padding - first baseline
    val placeableY = firstBaselineToTop.roundToPx() - firstBaseline
    val height = placeable.height + placeableY
    layout(placeable.width, height) {
        // Where the composable gets placed
        placeable.placeRelative(0, placeableY)
    }
}

इस कोड में यह हो रहा है:

  1. measurable लैम्डा पैरामीटर में, मेज़र किए जा सकने वाले पैरामीटर से दिखाए गए Text को measurable.measure(constraints) को कॉल करके मेज़र किया जाता है.
  2. layout(width, height) तरीके को कॉल करके, कंपोज़ेबल का साइज़ तय किया जाता है. इससे एक लैम्डा भी मिलता है, जिसका इस्तेमाल रैप किए गए एलिमेंट को प्लेस करने के लिए किया जाता है. इस मामले में, यह आखिरी बेसलाइन और जोड़ी गई टॉप पैडिंग के बीच की ऊंचाई है.
  3. placeable.place(x, y) को कॉल करके, रैप किए गए एलिमेंट को स्क्रीन पर पोज़िशन किया जाता है. अगर रैप किए गए एलिमेंट को प्लेस नहीं किया जाता है, तो वे नहीं दिखेंगे. y पोज़िशन, टॉप पैडिंग से जुड़ी होती है: टेक्स्ट की पहली बेसलाइन की पोज़िशन.

यह पुष्टि करने के लिए कि यह उम्मीद के मुताबिक काम करता है, Text पर इस मॉडिफ़ायर का इस्तेमाल करें:

@Preview
@Composable
fun TextWithPaddingToBaselinePreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.firstBaselineToTop(32.dp))
    }
}

@Preview
@Composable
fun TextWithNormalPaddingPreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.padding(top = 32.dp))
    }
}

टेक्स्ट एलिमेंट के कई प्रीव्यू; एक में एलिमेंट के बीच सामान्य पैडिंग दिखती है, दूसरे में एक बेसलाइन से दूसरी बेसलाइन तक की पैडिंग दिखती है.
इमेज 3. Text कंपोज़ेबल पर मॉडिफ़ायर लागू किया गया और इसका प्रीव्यू दिखाया गया.

कस्टम लेआउट बनाना

layout मॉडिफ़ायर, सिर्फ़ कॉल किए गए कंपोज़ेबल में बदलाव करता है. एक से ज़्यादा कंपोज़ेबल को मेज़र और लेआउट करने के लिए, इसके बजाय Layout कंपोज़ेबल का इस्तेमाल करें. इस कंपोज़ेबल की मदद से, चाइल्ड एलिमेंट को मैन्युअल तरीके से मेज़र और लेआउट किया जा सकता है. Column और Row जैसे सभी बड़े लेआउट, Layout कंपोज़ेबल की मदद से बनाए जाते हैं.

इस उदाहरण में, Column का बहुत ही बुनियादी वर्शन बनाया गया है. ज़्यादातर कस्टम लेआउट इस पैटर्न को फ़ॉलो करते हैं:

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // measure and position children given constraints logic here
        // ...
    }
}

layout मॉडिफ़ायर की तरह, measurables उन चाइल्ड एलिमेंट की सूची है जिन्हें मेज़र करना ज़रूरी है. वहीं, constraints पैरंट से मिलने वाले कंस्ट्रेंट हैं. पहले वाली ही लॉजिक को फ़ॉलो करते हुए, MyBasicColumn को इस तरह लागू किया जा सकता है:

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // Don't constrain child views further, measure them with given constraints
        // List of measured children
        val placeables = measurables.map { measurable ->
            // Measure each children
            measurable.measure(constraints)
        }

        // Set the size of the layout as big as it can
        layout(constraints.maxWidth, constraints.maxHeight) {
            // Track the y co-ord we have placed children up to
            var yPosition = 0

            // Place children in the parent layout
            placeables.forEach { placeable ->
                // Position item on the screen
                placeable.placeRelative(x = 0, y = yPosition)

                // Record the y co-ord placed up to
                yPosition += placeable.height
            }
        }
    }
}

चाइल्ड कंपोज़ेबल, Layout कंस्ट्रेंट (बिना minHeight कंस्ट्रेंट के) से सीमित होते हैं. साथ ही, उन्हें पिछले कंपोज़ेबल की yPosition के आधार पर प्लेस किया जाता है.

कस्टम कंपोज़ेबल का इस्तेमाल इस तरह किया जाएगा:

@Composable
fun CallingComposable(modifier: Modifier = Modifier) {
    MyBasicColumn(modifier.padding(8.dp)) {
        Text("MyBasicColumn")
        Text("places items")
        Text("vertically.")
        Text("We've done it by hand!")
    }
}

एक कॉलम में, एक के ऊपर एक रखे गए कई टेक्स्ट एलिमेंट.
इमेज 4. Column का कस्टम तरीके से लागू किया गया वर्शन.

लेआउट की दिशा

किसी कंपोज़ेबल के लेआउट की दिशा बदलने के लिए, LocalLayoutDirection कंपोज़िशन लोकल में बदलाव करें.

अगर कंपोज़ेबल को स्क्रीन पर मैन्युअल तरीके से प्लेस किया जा रहा है, तो LayoutDirection layout मॉडिफ़ायर या Layout कंपोज़ेबल के LayoutScope का हिस्सा होता है.

layoutDirection का इस्तेमाल करते समय, कंपोज़ेबल को place का इस्तेमाल करके प्लेस करें. placeRelative तरीके के उलट, place लेआउट की दिशा (बाएं से दाएं बनाम दाएं से बाएं) के आधार पर नहीं बदलता.

कस्टम लेआउट के इस्तेमाल के उदाहरण

Compose में बुनियादी लेआउट लेख में, लेआउट और मॉडिफ़ायर के बारे में ज़्यादा जानें. साथ ही, Compose के उन सैंपल में कस्टम लेआउट के इस्तेमाल के उदाहरण देखें जिनमें कस्टम लेआउट बनाए जाते हैं.

ज़्यादा जानें

Compose में कस्टम लेआउट के बारे में ज़्यादा जानने के लिए, ये अतिरिक्त संसाधन देखें.

वीडियो