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

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

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

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