Jetpack Compose में आर्किटेक्चर की लेयर जोड़ना

इस पेज पर, Jetpack Compose को बनाने वाली आर्किटेक्चरल लेयर के बारे में खास जानकारी दी गई है. साथ ही, इस डिज़ाइन के मुख्य सिद्धांतों के बारे में बताया गया है.

Jetpack Compose, एक ही बड़ा प्रोजेक्ट नहीं है. इसे कई मॉड्यूल से बनाया गया है, जिन्हें एक साथ जोड़कर पूरा स्टैक बनाया जाता है. Jetpack Compose को बनाने वाले अलग-अलग मॉड्यूल को समझने से, आपको ये काम करने में मदद मिलती है:

  • अपने ऐप्लिकेशन या लाइब्रेरी को बनाने के लिए, सही लेवल के ऐब्स्ट्रैक्शन का इस्तेमाल करें
  • यह समझना कि ज़्यादा कंट्रोल या कस्टमाइज़ेशन के लिए, कब निचले लेवल पर ‘ड्रॉप डाउन’ किया जा सकता है
  • डिपेंडेंसी कम करना

लेयर

Jetpack Compose की मुख्य लेयर ये हैं:

पहली इमेज. Jetpack Compose की मुख्य लेयर.

हर लेयर, निचले लेवल पर बनाई जाती है. इसमें फ़ंक्शन को जोड़कर, ज़्यादा लेवल वाले कॉम्पोनेंट बनाए जाते हैं. हर लेयर, अपने से नीचे की लेयर के सार्वजनिक एपीआई पर आधारित होती है. इससे मॉड्यूल की सीमाओं की पुष्टि की जा सकती है. साथ ही, ज़रूरत पड़ने पर किसी भी लेयर को बदला जा सकता है. आइए, इन लेयर को नीचे से ऊपर की ओर समझते हैं.

रनटाइम
इस मॉड्यूल में, Compose रनटाइम के बुनियादी सिद्धांतों के बारे में बताया गया है. जैसे, remember, mutableStateOf, @Composable एनोटेशन, और SideEffect. अगर आपको Compose के यूज़र इंटरफ़ेस (यूआई) की नहीं, बल्कि सिर्फ़ ट्री मैनेजमेंट की सुविधाओं की ज़रूरत है, तो सीधे इस लेयर पर काम किया जा सकता है.
यूज़र इंटरफ़ेस
यूज़र इंटरफ़ेस (यूआई) लेयर कई मॉड्यूल से बनी होती है ( ui-text, ui-graphics, ui-tooling, वगैरह). ये मॉड्यूल, यूज़र इंटरफ़ेस (यूआई) टूलकिट के बुनियादी फ़ंक्शन लागू करते हैं. जैसे, LayoutNode, Modifier, इनपुट हैंडलर, कस्टम लेआउट, और ड्रॉइंग. अगर आपको यूज़र इंटरफ़ेस (यूआई) टूलकिट के सिर्फ़ बुनियादी कॉन्सेप्ट की ज़रूरत है, तो इस लेयर पर काम किया जा सकता है.
Foundation
यह मॉड्यूल, Compose यूज़र इंटरफ़ेस (यूआई) के लिए डिज़ाइन सिस्टम के हिसाब से बिल्डिंग ब्लॉक उपलब्ध कराता है. जैसे, Row और Column, LazyColumn, खास जेस्चर की पहचान करना वगैरह. अपना डिज़ाइन सिस्टम बनाने के लिए, फ़ाउंडेशन लेयर का इस्तेमाल किया जा सकता है.
सामग्री
यह मॉड्यूल, Compose यूज़र इंटरफ़ेस (यूआई) के लिए मटीरियल डिज़ाइन सिस्टम को लागू करने की सुविधा देता है. इसमें थीम सिस्टम, स्टाइल वाले कॉम्पोनेंट, रिपल इंडिकेशन, और आइकॉन शामिल हैं. अपने ऐप्लिकेशन में मटीरियल डिज़ाइन का इस्तेमाल करते समय, इस लेयर का इस्तेमाल करें.

डिज़ाइन से जुड़े सिद्धांत

Jetpack Compose का मुख्य सिद्धांत, कुछ बड़े कॉम्पोनेंट के बजाय, छोटे और फ़ोकस किए गए फ़ंक्शन उपलब्ध कराना है. इन्हें एक साथ जोड़ा या कंपोज़ किया जा सकता है. इस तरीके के कई फ़ायदे हैं.

कंट्रोल

हायर लेवल कॉम्पोनेंट आपके लिए ज़्यादा काम करते हैं. हालांकि, इनमें आपको सीधे तौर पर कंट्रोल करने की सुविधा कम मिलती है. अगर आपको ज़्यादा कंट्रोल चाहिए, तो "ड्रॉप डाउन" करके, निचले लेवल के कॉम्पोनेंट का इस्तेमाल किया जा सकता है.

उदाहरण के लिए, अगर आपको किसी कॉम्पोनेंट के रंग को ऐनिमेट करना है, तो animateColorAsState एपीआई का इस्तेमाल किया जा सकता है:

val color = animateColorAsState(if (condition) Color.Green else Color.Red)

हालांकि, अगर आपको कॉम्पोनेंट को हमेशा ग्रे रंग से शुरू करना है, तो इस एपीआई का इस्तेमाल करके ऐसा नहीं किया जा सकता. इसके बजाय, लोअर लेवल Animatable एपीआई का इस्तेमाल किया जा सकता है:

val color = remember { Animatable(Color.Gray) }
LaunchedEffect(condition) {
    color.animateTo(if (condition) Color.Green else Color.Red)
}

हायर लेवल animateColorAsState एपीआई, लोअर लेवल Animatable एपीआई पर ही बनाया गया है. लोअर लेवल एपीआई का इस्तेमाल करना ज़्यादा मुश्किल है, लेकिन इससे ज़्यादा कंट्रोल मिलता है. अपनी ज़रूरत के हिसाब से एब्स्ट्रैक्शन का लेवल चुनें.

पसंद के मुताबिक बनाएं

छोटे बिल्डिंग ब्लॉक से बड़े कॉम्पोनेंट बनाने पर, कॉम्पोनेंट को ज़रूरत के हिसाब से पसंद के मुताबिक बनाना आसान हो जाता है. उदाहरण के लिए, मटीरियल लेयर से मिले Button के लागू करने के तरीके को देखें:

@Composable
fun Button(
    // …
    content: @Composable RowScope.() -> Unit
) {
    Surface(/* … */) {
        CompositionLocalProvider(/* … */) { // set LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                Row(
                    // …
                    content = content
                )
            }
        }
    }
}

Button को चार कॉम्पोनेंट से असेंबल किया जाता है:

  1. एक मटीरियल Surface जो बैकग्राउंड, आकार, क्लिक हैंडलिंग वगैरह उपलब्ध कराता है.

  2. A CompositionLocalProvider जो बटन के चालू या बंद होने पर, कॉन्टेंट के ऐल्फ़ा को बदलता है

  3. A ProvideTextStyle इस्तेमाल करने के लिए, डिफ़ॉल्ट टेक्स्ट स्टाइल सेट करता है

  4. Row, बटन के कॉन्टेंट के लिए डिफ़ॉल्ट लेआउट नीति उपलब्ध कराता है

हमने स्ट्रक्चर को ज़्यादा साफ़ तौर पर दिखाने के लिए, कुछ पैरामीटर और टिप्पणियों को हटा दिया है. हालांकि, पूरा कॉम्पोनेंट सिर्फ़ 40 लाइनों का कोड है, क्योंकि यह बटन को लागू करने के लिए, इन चार कॉम्पोनेंट को जोड़ता है. Button जैसे कॉम्पोनेंट, इस बारे में अपनी राय रखते हैं कि वे कौनसे पैरामीटर दिखाते हैं. साथ ही, वे सामान्य कस्टमाइज़ेशन को चालू करने और पैरामीटर की संख्या को संतुलित करने के बीच संतुलन बनाते हैं. इससे कॉम्पोनेंट को इस्तेमाल करना मुश्किल हो सकता है. उदाहरण के लिए, मटीरियल कॉम्पोनेंट, मटीरियल डिज़ाइन सिस्टम में बताई गई कस्टमाइज़ेशन की सुविधाएं देते हैं. इससे मटीरियल डिज़ाइन के सिद्धांतों का पालन करना आसान हो जाता है.

हालांकि, अगर आपको किसी कॉम्पोनेंट के पैरामीटर के अलावा, उसमें कोई और बदलाव करना है, तो "ड्रॉप डाउन" करके कॉम्पोनेंट को फ़ोर्क किया जा सकता है. उदाहरण के लिए, मटीरियल डिज़ाइन के मुताबिक, बटन का बैकग्राउंड एक ही रंग का होना चाहिए. अगर आपको ग्रेडिएंट बैकग्राउंड चाहिए, तो Button पैरामीटर के साथ यह विकल्प काम नहीं करता. इस मामले में, रेफ़रंस के तौर पर Material Button को लागू करने के तरीके का इस्तेमाल किया जा सकता है. साथ ही, अपना कॉम्पोनेंट बनाया जा सकता है:

@Composable
fun GradientButton(
    // …
    background: List<Color>,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(
                Brush.horizontalGradient(background)
            )
    ) {
        CompositionLocalProvider(/* … */) { // set material LocalContentAlpha
            ProvideTextStyle(MaterialTheme.typography.button) {
                content()
            }
        }
    }
}

ऊपर दिए गए कोड में, Material लेयर के कॉम्पोनेंट का इस्तेमाल जारी रहता है. जैसे, Material के कॉन्सेप्ट, जैसे कि मौजूदा कॉन्टेंट ऐल्फ़ा और मौजूदा टेक्स्ट स्टाइल. हालांकि, यह मटीरियल Surface को Row से बदल देता है और मनमुताबिक लुक पाने के लिए इसे स्टाइल करता है.

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

@Composable
fun BespokeButton(
    // …
    backgroundColor: Color,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Row(
        // …
        modifier = modifier
            .clickable(onClick = {})
            .background(backgroundColor)
    ) {
        // No Material components used
        content()
    }
}

Jetpack Compose, सबसे आसान नामों को सबसे ऊंचे लेवल के कॉम्पोनेंट के लिए रिज़र्व रखता है. उदाहरण के लिए, androidx.compose.material.Text को androidx.compose.foundation.text.BasicText के आधार पर बनाया गया है. इससे आपको अपने हिसाब से लागू करने की सुविधा मिलती है. साथ ही, अगर आपको ज़्यादा लेवल बदलने हैं, तो सबसे आसानी से खोजे जा सकने वाले नाम का इस्तेमाल करें.

सही एब्स्ट्रैक्शन चुनना

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

उदाहरण के लिए, अगर आपको अपने कस्टम कॉम्पोनेंट में जेस्चर की सुविधा जोड़नी है, तो Modifier.pointerInput का इस्तेमाल करके, इसे शुरू से बनाया जा सकता है. हालांकि, इसके ऊपर बने अन्य हाई लेवल कॉम्पोनेंट भी हैं जो बेहतर शुरुआती पॉइंट दे सकते हैं. उदाहरण के लिए, Modifier.draggable, Modifier.scrollable या Modifier.swipeable.

आम तौर पर, सबसे ऊंचे लेवल के कॉम्पोनेंट पर काम करना बेहतर होता है. इससे आपको अपनी ज़रूरत के हिसाब से फ़ंक्शनैलिटी मिलती है. साथ ही, कॉम्पोनेंट में शामिल सबसे सही तरीकों का फ़ायदा मिलता है.

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

कस्टम डिज़ाइन सिस्टम बनाने का उदाहरण देखने के लिए, Jetsnack सैंपल देखें.