स्टाइल की मदद से थीम बनाना

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

  1. पूरी तरह से कस्टम डिज़ाइन सिस्टम, जिसमें Material Design का इस्तेमाल नहीं किया गया है
    • सुझाव: थीम से वैल्यू इस्तेमाल करने वाली कॉम्पोनेंट स्टाइल तय करें. साथ ही, डिज़ाइन सिस्टम कॉम्पोनेंट पर स्टाइल पैरामीटर दिखाएं.
  2. मटीरियल डिज़ाइन का इस्तेमाल करना
    • सुझाव: स्टाइल के साथ इंटिग्रेट करने के लिए, Material के इस्तेमाल का इंतज़ार करें. जहां मुमकिन हो वहां अपने कॉम्पोनेंट पर स्टाइल का इस्तेमाल करें.

स्टाइल लेयर

Compose के पारंपरिक मॉडल में, पसंद के मुताबिक बनाने की सुविधा अक्सर MaterialTheme की ओर से उपलब्ध कराए गए ग्लोबल टोकन (रंग और टाइपोग्राफ़ी) को बदलने पर निर्भर करती है. इसके अलावा, जहां भी हो सके वहां डिज़ाइन सिस्टम के कंपोज़ेबल की प्रॉपर्टी को रैप और बदलने पर भी निर्भर करती है. कभी-कभी, मटेरियल लेयर में ऐसी प्रॉपर्टी होती हैं जिन्हें सबसिस्टम या पैरामीटर के ज़रिए नहीं दिखाया जाता. हालांकि, ये कॉम्पोनेंट पर हार्डकोड किए गए डिफ़ॉल्ट होते हैं.

Styles API में, ऐब्स्ट्रैक्शन की एक नई लेयर होती है. यह सबसिस्टम और कॉम्पोनेंट के बीच एक ब्रिज की तरह काम करती है: स्टाइल.

लेयर ज़िम्मेदारी उदाहरण
सबसिस्टम की वैल्यू नाम वाली वैल्यू val Primary = Color(0xFF34A85E)
ऐटम स्टाइल ऐसी स्टाइल जो सिर्फ़ एक प्रॉपर्टी में बदलाव करती है val buttonStyle = paddingAtomic then roundedCornerShapeAtomic then primaryBackgroundAtomic then largeSize then interactiveShadowAtomic
कॉम्पोनेंट स्टाइल कॉम्पोनेंट के हिसाब से कॉन्फ़िगरेशन प्राइमरी बैकग्राउंड और 16dp पैडिंग वाला बटन. val buttonStyle = Style { contentPadding(16.dp) shape(RoundedCornerShape(8.dp)) background(Color.Blue) }
कॉम्पोनेंट यह एक फ़ंक्शनल यूज़र इंटरफ़ेस (यूआई) एलिमेंट है, जो स्टाइल का इस्तेमाल करता है. Button(style = buttonStyle) { ... }
स्टाइल के साथ थीमिंग दिखाने वाला डायग्राम, जिसमें नई लेयर के बारे में बताया गया है
पहली इमेज. किसी कॉम्पोनेंट का उदाहरण और यह कि वह थीम से स्टाइल कैसे ऐक्सेस करता है.

ऐटॉमिक बनाम मोनोलिथिक स्टाइल

Styles API की मदद से, किसी स्टाइल को अलग-अलग ऐटम स्टाइल में बांटा जा सकता है. baseButtonStyle जैसी मुश्किल और कॉम्पोनेंट के हिसाब से स्टाइल तय करने के बजाय, एक ही मकसद के लिए छोटी-छोटी यूटिलिटी स्टाइल भी बनाई जा सकती हैं. ये आपके "ऐटम" के तौर पर काम करते हैं.

// Define single-purpose "atomic" styles
val paddingAtomic = Style {
    contentPadding(16.dp)
}
val roundedCornerShapeAtomic = Style {
    shape(RoundedCornerShape(8.dp))
}
val primaryBackgroundAtomic = Style {
    background(Color.Blue)
}
val largeSizeAtomic = Style {
    size(100.dp, 40.dp)
}
val interactiveShadowAtomic = Style {
    hovered {
        animate {
            dropShadow(
                Shadow(
                    offset = DpOffset(
                        0.dp,
                        0.dp
                    ),
                    radius = 2.dp,
                    spread = 0.dp,
                    color = Color.Blue,
                )
            )
        }
    }
}

"फिर" का इस्तेमाल करके कंपोज़िशन बनाना

नए Styles API की एक बेहतरीन सुविधा then ऑपरेटर है. इसकी मदद से, कई Style ऑब्जेक्ट को मर्ज किया जा सकता है. इससे आपको ऐटॉमिक यूटिलिटी क्लास का इस्तेमाल करके कॉम्पोनेंट बनाने की सुविधा मिलती है.

पारंपरिक (नॉन-ऐटॉमिक):

// One large monolithic style
val buttonStyle = Style {
    contentPadding(16.dp)
    shape(RoundedCornerShape(8.dp))
    background(Color.Blue)
}

एटॉमिक रीफ़ैक्टर:

// Combine atoms to create the final appearance
val buttonStyle = paddingAtomic then roundedCornerShapeAtomic then primaryBackgroundAtomic then interactiveShadowAtomic

अपने डिज़ाइन सिस्टम में स्टाइल इस्तेमाल करना

अपने डिज़ाइन सिस्टम में स्टाइल लागू करते समय, इन विकल्पों पर विचार करें. यह इस बात पर निर्भर करता है कि आपका डिज़ाइन सिस्टम स्पेक्ट्रम में कहां है.

स्टाइल के साथ पसंद के मुताबिक डिज़ाइन सिस्टम

इन स्थितियों में इस्तेमाल करें: आपको एक ऐसी ब्रैंड गाइड दी गई है जो मटीरियल डिज़ाइन पर आधारित नहीं है और आपको मटीरियल डिज़ाइन का इस्तेमाल नहीं करना है.

रणनीति: पूरी तरह से पसंद के मुताबिक डिज़ाइन सिस्टम लागू करें और स्टाइल को थीम के हिस्से के तौर पर दिखाएं.

अगर आपने Material को मुख्य डिज़ाइन सिस्टम की भाषा के तौर पर इस्तेमाल नहीं किया है, तो यह विकल्प कस्टम पाथ है. आपने विज़ुअल डेफ़िनिशन के लिए, MaterialTheme का इस्तेमाल नहीं किया है और आपने अपनी कस्टम थीम पहले ही बना ली है. एक CompanyTheme बनाएं, जो आपकी शैलियों के लिए कंटेनर का काम करता है.

  • यह कैसे काम करता है: एक CompanyTheme ऑब्जेक्ट बनाएं, जिसमें आपके सिस्टम के हर कॉम्पोनेंट के लिए Style ऑब्जेक्ट शामिल हों. आपके कॉम्पोनेंट (मटेरियल लॉजिक के आस-पास रैपर या कस्टम Box या Layout लागू करने की सुविधा) इन स्टाइल का सीधे तौर पर इस्तेमाल करते हैं. साथ ही, आपके डिज़ाइन सिस्टम के उपभोक्ताओं के लिए Style पैरामीटर दिखाते हैं.
  • स्टाइल लेयर: स्टाइल, आपके डिज़ाइन सिस्टम की मुख्य परिभाषा होती हैं. टोकन, स्टाइल में इस्तेमाल किए जाने वाले वैरिएबल होते हैं. इससे, डीप कस्टमाइज़ेशन किया जा सकता है. जैसे, स्थिति में बदलाव के लिए यूनीक ऐनिमेशन तय करना. उदाहरण के लिए, दबाने पर स्केल और रंग को ऐनिमेट करना.

अगर Material का इस्तेमाल किए बिना, कस्टम थीम बनाई जा रही है और आपको स्टाइल अपनानी हैं, तो अपनी थीम में स्टाइल की सूची जोड़ें. इससे आपको अपने प्रोजेक्ट में कहीं से भी, बेस स्टाइल ऐक्सेस करने की सुविधा मिलती है.

  1. एक Styles क्लास बनाएं. यह क्लास, आपके ऐप्लिकेशन में अलग-अलग स्टाइल सेव करती है और डिफ़ॉल्ट स्टाइल बनाती है. उदाहरण के लिए, Jetsnack ऐप्लिकेशन में क्लास का नाम JetsnackStyles है:

    object JetsnackStyles{
        val buttonStyle: Style = Style {
            shape(shapes.medium)
            background(colors.brand)
            contentColor(colors.textPrimary)
            contentPaddingVertical(8.dp)
            contentPaddingHorizontal(24.dp)
            textStyle(typography.labelLarge)
            disabled {
                animate {
                    background(colors.brandSecondary)
                }
            }
        }
        val cardStyle: Style = Style {
            shape(shapes.medium)
            background(colors.uiBackground)
            contentColor(colors.textPrimary)
        }
    }

  2. अपनी थीम के हिस्से के तौर पर Styles उपलब्ध कराएं. साथ ही, सबसिस्टम को ऐक्सेस करने के लिए, Styles पर हेल्पर एक्सटेंशन फ़ंक्शन दिखाएं:StyleScope

    @Immutable
    class JetsnackTheme(
        val colors: JetsnackColors = LightJetsnackColors,
        val typography: androidx.compose.material3.Typography = androidx.compose.material3.Typography(),
        val shapes: Shapes = Shapes()
    ) {
        companion object {
            val colors: JetsnackColors
                @Composable @ReadOnlyComposable
                get() = LocalJetsnackTheme.current.colors
    
            val typography: androidx.compose.material3.Typography
                @Composable @ReadOnlyComposable
                get() = LocalJetsnackTheme.current.typography
    
            val shapes: Shapes
                @Composable @ReadOnlyComposable
                get() = LocalJetsnackTheme.current.shapes
    
            val styles: JetsnackStyles = JetsnackStyles
    
            val LocalJetsnackTheme: ProvidableCompositionLocal<JetsnackTheme>
                get() = LocalJetsnackThemeInstance
        }
    }
    
    val StyleScope.colors: JetsnackColors
        get() = LocalJetsnackTheme.currentValue.colors
    
    val StyleScope.typography: androidx.compose.material3.Typography
        get() = LocalJetsnackTheme.currentValue.typography
    
    val StyleScope.shapes: Shapes
        get() = LocalJetsnackTheme.currentValue.shapes
    
    internal val LocalJetsnackThemeInstance = staticCompositionLocalOf { JetsnackTheme() }
    
    @Composable
    fun JetsnackTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
        val colors = if (darkTheme) DarkJetsnackColors else LightJetsnackColors
        val theme = JetsnackTheme(colors = colors)
    
        CompositionLocalProvider(
            LocalJetsnackTheme provides theme,
        ) {
            MaterialTheme(
                typography = LocalJetsnackTheme.current.typography,
                shapes = LocalJetsnackTheme.current.shapes,
                content = content,
            )
        }
    }

  3. अपने कंपोज़ेबल में JetsnackStyles को ऐक्सेस करें:

    @Composable
    fun CustomButton(modifier: Modifier,
                     style: Style = Style,
                     text: String) {
        val interactionSource = remember { MutableInteractionSource() }
        val styleState = remember(interactionSource) { MutableStyleState(interactionSource) }
    
        // Apply style to top level container in combination with incoming style from parameter.
        Box(modifier = modifier
            .clickable(
                interactionSource = interactionSource,
                indication = null,
                enabled = true,
                role = Role.Button,
                onClick = {
    
                },
            )
            .styleable(styleState, JetsnackTheme.styles.buttonStyle, style)) {
            Text(text)
        }
    }

ग्लोबल थीम को अपनाने के अलावा, अपने ऐप्लिकेशन में Styles को शामिल करने के लिए अन्य रणनीतियां भी हैं. Styles का इस्तेमाल, कॉल करने की कुछ खास साइटों के लिए किया जा सकता है. इसके अलावा, जब पूरी थीमिंग की सुविधाओं की ज़रूरत न हो, तब स्टैटिक परिभाषाओं का इस्तेमाल किया जा सकता है. Styles को कंडीशनल तौर पर तब तक नहीं बदला जाना चाहिए, जब तक कि पूरी स्टाइल बुनियादी तौर पर अलग न हो. आपको अलग-अलग स्टाइल ऑब्जेक्ट के बीच स्विच करने के बजाय, विज़ुअल डेफ़िनिशन के अंदर डाइनैमिक टोकन ऐक्सेस करने चाहिए.