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

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

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

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

परतें

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

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

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

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

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

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 एपीआई पर ही बनाया गया है. लोअर लेवल एपीआई का इस्तेमाल करना ज़्यादा मुश्किल है, लेकिन इससे ज़्यादा कंट्रोल मिलता है. अपनी ज़रूरत के हिसाब से, ऐब्स्ट्रैक्शन का लेवल चुनें.

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

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

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

ऊपर दिए गए उदाहरण में, 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 का सैंपल देखें.