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

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

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

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

परतें

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

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

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

रनटाइम
इस मॉड्यूल में, Compose रनटाइम की बुनियादी बातें बताई गई हैं. जैसे, remember, mutableStateOf, @Composable एनोटेशन, और SideEffect. अगर आपको सिर्फ़ कंपोज़ की ट्री मैनेजमेंट क्षमताओं की ज़रूरत है, तो इसके यूज़र इंटरफ़ेस (यूआई) की ज़रूरत नहीं है, तो आप सीधे इस लेयर का इस्तेमाल करने पर विचार कर सकते हैं.
यूज़र इंटरफ़ेस (यूआई)
यूज़र इंटरफ़ेस (यूआई) लेयर, कई मॉड्यूल ( ui-text, ui-graphics, ui-tooling वगैरह) से बनी होती है. ये मॉड्यूल, यूआई टूलकिट के बुनियादी फ़ंक्शन लागू करते हैं. जैसे, LayoutNode, Modifier, इनपुट हैंडलर, पसंद के मुताबिक लेआउट, और ड्रॉइंग. अगर आपको सिर्फ़ यूज़र इंटरफ़ेस टूलकिट के बुनियादी कॉन्सेप्ट चाहिए, तो इस लेयर पर काम करें.
फ़ाउंडेशन
यह मॉड्यूल, 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. ऐसा CompositionLocalProvider जो बटन के चालू या बंद होने पर, कॉन्टेंट के अल्फा को बदलता है

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

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

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

हालांकि, अगर आपको कॉम्पोनेंट के पैरामीटर के अलावा, कॉम्पोनेंट को पसंद के मुताबिक बनाना है, तो किसी लेवल को "ड्रॉप-डाउन" करके कॉम्पोनेंट को फ़ोर्क किया जा सकता है. उदाहरण के लिए, Material Design के मुताबिक बटन का बैकग्राउंड एक ही रंग का होना चाहिए. अगर आपको ग्रेडिएंट बैकग्राउंड की ज़रूरत है, तो यह विकल्प 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()
            }
        }
    }
}

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

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

@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 का सैंपल देखें.