Compose में मटीरियल डिज़ाइन 2

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

Jetpack Compose, इन कॉन्सेप्ट को MaterialTheme composable के साथ लागू करता है:

MaterialTheme(
    colors = // ...
    typography = // ...
    shapes = // ...
) {
    // app content
}

अपने ऐप्लिकेशन को थीम देने के लिए, MaterialTheme को पास किए गए पैरामीटर कॉन्फ़िगर करें.

दो कंट्रास्ट वाले स्क्रीनशॉट. पहला विकल्प, डिफ़ॉल्ट Materialथीम स्टाइलिंग का इस्तेमाल करता है,
दूसरे स्क्रीनशॉट में, बदली गई स्टाइल का इस्तेमाल किया गया है.

पहली इमेज. पहला स्क्रीनशॉट ऐसा ऐप्लिकेशन दिखाता है जो कॉन्फ़िगर नहीं हो रहा है MaterialTheme सेट किया गया है. इसलिए, यह डिफ़ॉल्ट स्टाइल का इस्तेमाल करता है. दूसरे स्क्रीनशॉट में ऐसा ऐप्लिकेशन जो स्टाइल को पसंद के मुताबिक बनाने के लिए, MaterialTheme को पैरामीटर पास करता है.

रंग

Compose में Color क्लास की मदद से कलर को मॉडल किया जाता है, यह एक आसान तरीका है डेटा होल्डिंग क्लास.

val Red = Color(0xffff0000)
val Blue = Color(red = 0f, green = 0f, blue = 1f)

इन्हें अपनी पसंद के मुताबिक व्यवस्थित किया जा सकता है. जैसे, टॉप-लेवल कॉन्स्टेंट के तौर पर, सिंगलटन में या इनलाइन में तय किया गया. हालांकि, हमारा सख्त सुझाव है कि अपनी थीम में रंग तय करें और वहां से रंगों को वापस पाएं. इस तरीके से, गहरे रंग वाली थीम और नेस्ट की गई थीम को आसानी से इस्तेमाल किया जा सकता है.

थीम के कलर पैलेट का उदाहरण

दूसरी इमेज. मटीरियल कलर सिस्टम.

लिखने से Colors मिलती है क्लास को मॉडल करने के लिए मटीरियल कलर सिस्टम. Colors से मिलते हैं लाइट के सेट बनाने के लिए फ़ंक्शन बिल्डर या गहरे रंग वाली रंग:

private val Yellow200 = Color(0xffffeb46)
private val Blue200 = Color(0xff91a4fc)
// ...

private val DarkColors = darkColors(
    primary = Yellow200,
    secondary = Blue200,
    // ...
)
private val LightColors = lightColors(
    primary = Yellow500,
    primaryVariant = Yellow400,
    secondary = Blue700,
    // ...
)

Colors तय करने के बाद, उन्हें MaterialTheme को पास किया जा सकता है:

MaterialTheme(
    colors = if (darkTheme) DarkColors else LightColors
) {
    // app content
}

थीम के रंगों का इस्तेमाल करना

MaterialTheme कंपोज़ेबल को दिए गए Colors को वापस लाया जा सकता है MaterialTheme.colors का इस्तेमाल करके.

Text(
    text = "Hello theming",
    color = MaterialTheme.colors.primary
)

प्लैटफ़ॉर्म और कॉन्टेंट का रंग

कई कॉम्पोनेंट रंग और कॉन्टेंट के रंग, दोनों को स्वीकार करते हैं:

Surface(
    color = MaterialTheme.colors.surface,
    contentColor = contentColorFor(color),
    // ...
) { /* ... */ }

TopAppBar(
    backgroundColor = MaterialTheme.colors.primarySurface,
    contentColor = contentColorFor(backgroundColor),
    // ...
) { /* ... */ }

इससे, न सिर्फ़ किसी कॉम्पोज़ेबल का रंग सेट किया जा सकता है, बल्कि कॉन्टेंट और उसमें मौजूद कॉम्पोज़ेबल के लिए डिफ़ॉल्ट रंग भी दिया जा सकता है. कई कंपोज़ेबल में कॉन्टेंट के इस रंग का इस्तेमाल डिफ़ॉल्ट रूप से किया जाता है. उदाहरण के लिए, Text का रंग, उसके पैरंट कॉम्पोनेंट के कॉन्टेंट के रंग पर आधारित होता है. साथ ही, Icon अपने रंग को सेट करने के लिए, उस रंग का इस्तेमाल करता है.

अलग-अलग रंगों वाले एक ही बैनर के दो उदाहरण

तीसरी इमेज. बैकग्राउंड के अलग-अलग रंग सेट करने पर, टेक्स्ट और आइकॉन के रंग भी अलग-अलग हो जाते हैं.

contentColorFor() यह तरीका सही "चालू है" का इस्तेमाल करता है किसी भी थीम के कलर के लिए रंग. उदाहरण के लिए, अगर आपने Surface पर primary बैकग्राउंड रंग सेट किया है, तो यह फ़ंक्शन onPrimary को कॉन्टेंट के रंग के तौर पर सेट करने के लिए इस्तेमाल किया जाता है. अगर बिना थीम वाला कोई बैकग्राउंड कलर सेट किया जाता है, तो आपको का रंग सही होना चाहिए. मौजूदा बैकग्राउंड के लिए, पसंदीदा कॉन्टेंट का रंग पाने के लिए, LocalContentColor का इस्तेमाल करें.

सामग्री ऐल्फ़ा

आम तौर पर, किसी कॉन्टेंट की अहमियत के बारे में बताने के लिए, अक्सर आप अलग-अलग तरह का तरीका चुनते हैं साथ ही, विज़ुअल हैरारकी भी उपलब्ध कराई जा सकती है. Material Design के मुताबिक, टेक्स्ट को आसानी से पढ़ने के लिए सुझाव में, अलग-अलग लेवल की ओपैसिटी का इस्तेमाल करने का सुझाव दिया गया है. इससे, टेक्स्ट के अलग-अलग लेवल की अहमियत को बताया जा सकता है.

Jetpack Compose इसे LocalContentAlpha की मदद से लागू करता है. किसी हैरारकी के लिए कॉन्टेंट अल्फा तय करने के लिए, इस CompositionLocal के लिए वैल्यू दें. नेस्ट किए गए कॉम्पोज़ेबल, अपने कॉन्टेंट पर अल्फा ट्रैटमेंट लागू करने के लिए इस वैल्यू का इस्तेमाल कर सकते हैं. उदाहरण के लिए, Text और Icon डिफ़ॉल्ट रूप से LocalContentColor का कॉम्बिनेशन इस्तेमाल करें, जो LocalContentAlpha के लिए अडजस्ट किए गए है. सामग्री में कुछ स्टैंडर्ड ऐल्फ़ा वैल्यू दी गई हैं (high, medium, disabled) को ContentAlpha ऑब्जेक्ट से बनाया गया है.

// By default, both Icon & Text use the combination of LocalContentColor &
// LocalContentAlpha. De-emphasize content by setting content alpha
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
    Text(
        // ...
    )
}
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
    Icon(
        // ...
    )
    Text(
        // ...
    )
}

CompositionLocal के बारे में ज़्यादा जानने के लिए, इस सुविधा के साथ स्थानीय तौर पर स्कोप वाला डेटा देखें कंपोज़िशन लोकल गाइड.

किसी लेख के शीर्षक का स्क्रीनशॉट, जिसमें टेक्स्ट को अलग-अलग लेवल पर हाइलाइट किया गया है

चौथी इमेज. विज़ुअल के रूप में बातचीत करने के लिए, टेक्स्ट पर अलग-अलग फ़ोकस के लेवल लागू करें सूचना की हैरारकी है. टेक्स्ट की पहली लाइन का टाइटल होता है. इसमें टाइटल होता है सबसे अहम जानकारी शामिल करती है और ContentAlpha.high का इस्तेमाल करती है. दूसरा इस लाइन में कम ज़रूरी मेटाडेटा होता है और इसलिए, ContentAlpha.medium का इस्तेमाल किया जाता है.

गहरे रंग वाली थीम

Compose में, MaterialTheme कॉम्पोज़ेबल के लिए Colors के अलग-अलग सेट उपलब्ध कराकर, हल्की और गहरे रंग वाली थीम लागू की जा सकती हैं:

@Composable
fun MyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    MaterialTheme(
        colors = if (darkTheme) DarkColors else LightColors,
        /*...*/
        content = content
    )
}

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

इस तरह के कोड का इस्तेमाल करके, यह देखा जा सकता है कि मौजूदा Colors हल्के हैं या गहरे रंग के हैं:

val isLightTheme = MaterialTheme.colors.isLight
Icon(
    painterResource(
        id = if (isLightTheme) {
            R.drawable.ic_sun_24
        } else {
            R.drawable.ic_moon_24
        }
    ),
    contentDescription = "Theme"
)

ऊंचाई के ओवरले

मटीरियल में, ज़्यादा ऊंचाई वाली गहरे रंग वाली थीम में सरफ़ेस मिलते हैं चढ़ाई ओवरले करते हैं, जो बैकग्राउंड को हल्का कर देता है. किसी सतह की ऊंचाई जितनी ज़्यादा होगी (उसे नज़दीक करना करने से पहले, रोशनी का स्तर हल्का हो जाता है.

ये ओवरले, Surface कॉम्पोज़ेबल की मदद से, गहरे रंगों का इस्तेमाल करने पर अपने-आप लागू हो जाते हैं. साथ ही, ये किसी भी ऐसे Material कॉम्पोज़ेबल के लिए लागू होते हैं जो किसी सतह का इस्तेमाल करता है:

Surface(
    elevation = 2.dp,
    color = MaterialTheme.colors.surface, // color will be adjusted for elevation
    /*...*/
) { /*...*/ }

किसी ऐप्लिकेशन का स्क्रीनशॉट, जिसमें अलग-अलग ऊंचाई के लेवल पर एलिमेंट के लिए इस्तेमाल किए गए रंगों में थोड़ा अंतर दिख रहा है

पांचवी इमेज. कार्ड और सबसे नीचे मौजूद नेविगेशन, दोनों में ही surface रंग का इस्तेमाल किया गया है बैकग्राउंड के तौर पर रखा जा सकता है. कार्ड और सबसे नीचे वाला नेविगेशन, दोनों अलग-अलग होते हैं पृष्ठभूमि के ऊपर ऊंचाई स्तर, वे थोड़े अलग हैं रंग–कार्ड बैकग्राउंड से हल्के होते हैं और नीचे मौजूद नेविगेशन कार्ड से हल्का होता है.

पसंद के मुताबिक बनाए गए ऐसे मामलों के लिए जिनमें Surface शामिल न हो, इसका इस्तेमाल करें LocalElevationOverlay, एक CompositionLocal जिसमें ElevationOverlay इस्तेमाल करने वाले Surface घटक:

// Elevation overlays
// Implemented in Surface (and any components that use it)
val color = MaterialTheme.colors.surface
val elevation = 4.dp
val overlaidColor = LocalElevationOverlay.current?.apply(
    color, elevation
)

ऊंचाई के ओवरले बंद करने के लिए, कॉम्पोज़ की जा सकने वाली हैरारकी में अपनी पसंद के पॉइंट पर null डालें:

MyTheme {
    CompositionLocalProvider(LocalElevationOverlay provides null) {
        // Content without elevation overlays
    }
}

सीमित रंग के ऐक्सेंट

सामग्री सीमित रंग लागू करने का सुझाव देती है गहरे रंग के लिए उच्चारण इनमें primary रंग के बजाय surface रंग के इस्तेमाल को प्राथमिकता देकर थीम ज़्यादातर मामलों में. TopAppBar और BottomNavigation जैसे कॉम्पोज़ेबल, डिफ़ॉल्ट रूप से इस व्यवहार को लागू करते हैं.

छठी इमेज. सीमित रंगों वाली मटीरियल डार्क थीम. सबसे ऊपर मौजूद ऐप्लिकेशन बार इसमें हल्के रंग वाली थीम के मुख्य रंग और गहरे रंग वाली थीम में सरफ़ेस के रंग का इस्तेमाल किया गया है.

कस्टम स्थितियों के लिए, primarySurface एक्सटेंशन प्रॉपर्टी का इस्तेमाल करें:

Surface(
    // Switches between primary in light theme and surface in dark theme
    color = MaterialTheme.colors.primarySurface,
    /*...*/
) { /*...*/ }

मुद्रण कला

Material में टाइप सिस्टम तय किया जाता है. इससे, आपको कम संख्या में ऐसे स्टाइल इस्तेमाल करने के लिए बढ़ावा मिलता है जिनके नाम से उनके काम के बारे में पता चलता हो.

अलग-अलग स्टाइल में कई अलग-अलग टाइपफ़ेस का उदाहरण

सातवीं इमेज. मटीरियल टाइप सिस्टम.

Compose, टाइप सिस्टम को Typography, TextStyle, और फ़ॉन्ट से जुड़ी क्लास के साथ लागू करता है. Typography कंस्ट्रक्टर, हर स्टाइल के लिए डिफ़ॉल्ट विकल्प देता है, ताकि आप ऐसी किसी भी स्टाइल को छोड़ सकें जिसे आपको पसंद के मुताबिक नहीं बनाना है:

val raleway = FontFamily(
    Font(R.font.raleway_regular),
    Font(R.font.raleway_medium, FontWeight.W500),
    Font(R.font.raleway_semibold, FontWeight.SemiBold)
)

val myTypography = Typography(
    h1 = TextStyle(
        fontFamily = raleway,
        fontWeight = FontWeight.W300,
        fontSize = 96.sp
    ),
    body1 = TextStyle(
        fontFamily = raleway,
        fontWeight = FontWeight.W600,
        fontSize = 16.sp
    )
    /*...*/
)
MaterialTheme(typography = myTypography, /*...*/) {
    /*...*/
}

अगर आपको पूरे टेक्स्ट में एक ही टाइपफ़ेस का इस्तेमाल करना है, तो defaultFontFamily parameter और किसी भी TextStyle एलिमेंट के fontFamily को हटा दें:

val typography = Typography(defaultFontFamily = raleway)
MaterialTheme(typography = typography, /*...*/) {
    /*...*/
}

टेक्स्ट स्टाइल का इस्तेमाल करना

TextStyle को MaterialTheme.typography के ज़रिए ऐक्सेस किया जाता है. वापस पाएं TextStyle को यह पसंद है:

Text(
    text = "Subtitle2 styled",
    style = MaterialTheme.typography.subtitle2
)

अलग-अलग कामों के लिए, अलग-अलग टाइपफ़ेस दिखाने वाला स्क्रीनशॉट

आठवीं इमेज. अपने ब्रैंड को ज़ाहिर करने के लिए, अलग-अलग टाइपफ़ेस और स्टाइल का इस्तेमाल करें.

आकार

Material में आकार के सिस्टम की जानकारी होती है. इससे आपको बड़े, मध्यम, और छोटे कॉम्पोनेंट के लिए आकार तय करने में मदद मिलती है.

अलग-अलग मटीरियल डिज़ाइन आकार दिखाता है

नौवीं इमेज. मटीरियल का शेप सिस्टम.

Compose, Shapes क्लास की मदद से आकार सिस्टम लागू करता है. इसकी मदद से, हर साइज़ कैटगरी के लिए CornerBasedShape तय किया जा सकता है:

val shapes = Shapes(
    small = RoundedCornerShape(percent = 50),
    medium = RoundedCornerShape(0f),
    large = CutCornerShape(
        topStart = 16.dp,
        topEnd = 0.dp,
        bottomEnd = 0.dp,
        bottomStart = 16.dp
    )
)

MaterialTheme(shapes = shapes, /*...*/) {
    /*...*/
}

कई कॉम्पोनेंट डिफ़ॉल्ट रूप से इन आकारों का इस्तेमाल करते हैं. उदाहरण के लिए, Button TextField, और FloatingActionButton डिफ़ॉल्ट रूप से छोटा हो, AlertDialog डिफ़ॉल्ट रूप से मीडियम होता है और ModalDrawer डिफ़ॉल्ट रूप से बड़ा होता है — आकार स्कीम का संदर्भ पूरी मैपिंग के लिए किया जा सकता है.

आकृतियों का उपयोग करना

Shape को MaterialTheme.shapes के ज़रिए ऐक्सेस किया जाता है. इस तरह से कोड के साथ Shapes पाएं:

Surface(
    shape = MaterialTheme.shapes.medium, /*...*/
) {
    /*...*/
}

मटीरियल शेप का इस्तेमाल करके, एलिमेंट की स्थिति बताने वाले ऐप्लिकेशन का स्क्रीनशॉट

10वीं इमेज. ब्रैंड या राज्य के बारे में बताने के लिए, आकार का इस्तेमाल करें.

डिफ़ॉल्ट स्टाइल

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

@Composable
fun MyButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Button(
        colors = ButtonDefaults.buttonColors(
            backgroundColor = MaterialTheme.colors.secondary
        ),
        onClick = onClick,
        modifier = modifier,
        content = content
    )
}

थीम ओवरले

ऐसा करके, आपकी मदद से कंपोज़ में Android व्यू से मिले थीम ओवरले को नेस्ट करके MaterialTheme कंपोज़ेबल. क्योंकि MaterialTheme थीम की मौजूदा वैल्यू के हिसाब से रंग, टाइपोग्राफ़ी, और आकारों को डिफ़ॉल्ट रूप से सेट कर देता है. अगर कोई थीम इनमें से किसी एक पैरामीटर को ही सेट करती है, तो दूसरे पैरामीटर की डिफ़ॉल्ट वैल्यू बनी रहती है.

इसके अलावा, व्यू पर आधारित स्क्रीन को Compose में माइग्रेट करते समय, android:theme एट्रिब्यूट के इस्तेमाल पर ध्यान दें. आपको शायद एक नए MaterialTheme हो, जो 'लिखें' यूज़र इंटरफ़ेस (यूआई) ट्री के उस हिस्से में मौजूद हो.

इस उदाहरण में, ज़्यादातर स्क्रीन के लिए PinkTheme और मिलते-जुलते सेक्शन के लिए BlueTheme का इस्तेमाल किया गया है. नीचे स्क्रीनशॉट और कोड देखें.

11वीं इमेज. नेस्ट की गई थीम.

@Composable
fun DetailsScreen(/* ... */) {
    PinkTheme {
        // other content
        RelatedSection()
    }
}

@Composable
fun RelatedSection(/* ... */) {
    BlueTheme {
        // content
    }
}

कॉम्पोनेंट की स्थितियां

जिन मटीरियल कॉम्पोनेंट के साथ इंटरैक्ट किया जा सकता है (क्लिक किया जा सकता है, टॉगल किया जा सकता है वगैरह), वे अलग-अलग विज़ुअल स्टेटस में हो सकते हैं. स्थितियों में चालू, बंद, दबाया गया वगैरह शामिल हैं.

कंपोज़ेबल में अक्सर enabled पैरामीटर होता है. इसे false पर सेट करने से, इंटरैक्शन पर रोक लगती है. साथ ही, रंग और ऊंचाई जैसी प्रॉपर्टी में बदलाव होता है, ताकि कॉम्पोनेंट की स्थिति को विज़ुअल तौर पर दिखाया जा सके.

12वीं इमेज. enabled = true (बाएं) और enabled = false वाला बटन (दाएं).

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

Button(
    onClick = { /* ... */ },
    enabled = true,
    // Custom colors for different states
    colors = ButtonDefaults.buttonColors(
        backgroundColor = MaterialTheme.colors.secondary,
        disabledBackgroundColor = MaterialTheme.colors.onBackground
            .copy(alpha = 0.2f)
            .compositeOver(MaterialTheme.colors.background)
        // Also contentColor and disabledContentColor
    ),
    // Custom elevation for different states
    elevation = ButtonDefaults.elevation(
        defaultElevation = 8.dp,
        disabledElevation = 2.dp,
        // Also pressedElevation
    )
) { /* ... */ }

13वीं इमेज. enabled = true (बाईं ओर) और enabled = false (दाईं ओर) वाला बटन, जिसमें रंग और ऊंचाई की वैल्यू में बदलाव किया गया है.

लहरें

मैटेरियल कॉम्पोनेंट, रिपल का इस्तेमाल करके यह दिखाते हैं कि उनसे इंटरैक्ट किया जा रहा है. अगर आपने आप अपने क्रम में MaterialTheme का इस्तेमाल कर रहे हैं, तो Ripple का इस्तेमाल डिफ़ॉल्टIndication इस तरह के कार्रवाई के लिए, clickable और indication.

ज़्यादातर मामलों में, डिफ़ॉल्ट Ripple पर भरोसा किया जा सकता है. अगर आपको इनका रंग और अल्फा जैसी प्रॉपर्टी बदलनी हैं, तो RippleTheme का इस्तेमाल करें.

आप RippleTheme की अवधि बढ़ा सकते हैं और defaultRippleColor और defaultRippleAlpha उपयोगिता फ़ंक्शन. इसके बाद, कस्टम रिपल थीम को क्रम से लगाने के लिए इनका इस्तेमाल किया जा सकता है LocalRippleTheme:

@Composable
fun MyApp() {
    MaterialTheme {
        CompositionLocalProvider(
            LocalRippleTheme provides SecondaryRippleTheme
        ) {
            // App content
        }
    }
}

@Immutable
private object SecondaryRippleTheme : RippleTheme {
    @Composable
    override fun defaultColor() = RippleTheme.defaultRippleColor(
        contentColor = MaterialTheme.colors.secondary,
        lightTheme = MaterialTheme.colors.isLight
    )

    @Composable
    override fun rippleAlpha() = RippleTheme.defaultRippleAlpha(
        contentColor = MaterialTheme.colors.secondary,
        lightTheme = MaterialTheme.colors.isLight
    )
}

alt_text

14वीं इमेज. RippleTheme के ज़रिए अलग-अलग रिपल वैल्यू वाले बटन.

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

Compose में मटीरियल थीमिंग के बारे में ज़्यादा जानने के लिए, ये देखें अतिरिक्त संसाधन शामिल करें.

कोड लैब

वीडियो