शैडो से आपके यूज़र इंटरफ़ेस (यूआई) को विज़ुअल तौर पर बेहतर बनाया जाता है. साथ ही, इससे लोगों को इंटरैक्टिविटी के बारे में पता चलता है और उन्हें उपयोगकर्ता की कार्रवाइयों के बारे में तुरंत जानकारी मिलती है. Compose, आपके ऐप्लिकेशन में शैडो शामिल करने के कई तरीके उपलब्ध कराता है:
Modifier.shadow(): यह कंपोज़ेबल के पीछे, ऊंचाई के आधार पर एक शैडो बनाता है. यह शैडो, मटीरियल डिज़ाइन के दिशा-निर्देशों के मुताबिक होती है.Modifier.dropShadow(): इससे कस्टमाइज़ की जा सकने वाली एक ऐसी शैडो बनती है जो कंपोज़ेबल के पीछे दिखती है. इससे कंपोज़ेबल ऊंचा दिखता है.Modifier.innerShadow(): यह कंपोज़ेबल के बॉर्डर के अंदर शैडो बनाता है. इससे ऐसा लगता है कि कंपोज़ेबल को उसके पीछे की सतह में दबा दिया गया है.
Modifier.shadow() का इस्तेमाल, सामान्य शैडो बनाने के लिए किया जाता है. वहीं, dropShadow() और innerShadow() मॉडिफ़ायर, शैडो रेंडरिंग पर ज़्यादा कंट्रोल और सटीक जानकारी देते हैं.
इस पेज पर, इन सभी मॉडिफ़ायर को लागू करने का तरीका बताया गया है. इसमें यह भी बताया गया है कि उपयोगकर्ता के इंटरैक्शन पर शैडो को ऐनिमेट कैसे करें. साथ ही, innerShadow() और dropShadow() मॉडिफ़ायर को एक साथ इस्तेमाल करके, ग्रेडिएंट शैडो, न्यूमॉर्फ़िक शैडो वगैरह कैसे बनाएं.
बेसिक शैडो बनाना
Modifier.shadow(), मटेरियल डिज़ाइन के दिशा-निर्देशों के मुताबिक एक सामान्य शैडो बनाता है. इससे ऐसा लगता है कि रोशनी ऊपर से आ रही है. शैडो की गहराई, elevation वैल्यू पर आधारित होती है. साथ ही, कास्ट शैडो को कंपोज़ेबल के आकार के हिसाब से काटा जाता है.
@Composable fun ElevationBasedShadow() { Box( modifier = Modifier.aspectRatio(1f).fillMaxSize(), contentAlignment = Alignment.Center ) { Box( Modifier .size(100.dp, 100.dp) .shadow(10.dp, RectangleShape) .background(Color.White) ) } }
Modifier.shadow() की मदद से बनाई गई, ऊंचाई के आधार पर शैडो.ड्रॉप शैडो लागू करना
अपने कॉन्टेंट के पीछे सटीक शैडो बनाने के लिए, dropShadow() मॉडिफ़ायर का इस्तेमाल करें. इससे एलिमेंट ऊपर की ओर उठा हुआ दिखता है.
इसके Shadow पैरामीटर की मदद से, इन मुख्य पहलुओं को कंट्रोल किया जा सकता है:
radius: इससे धुंधलेपन की तीव्रता और फैलाव तय होता है.color: इससे रंगत का रंग तय होता है.offset: इससे शैडो की ज्यामिति को x और y ऐक्सिस पर रखा जाता है.spread: इससे शैडो की ज्यामिति को बड़ा या छोटा किया जा सकता है.
इसके अलावा, shape पैरामीटर से शैडो के पूरे आकार के बारे में पता चलता है. यह androidx.compose.foundation.shape पैकेज के साथ-साथ, Material Expressive shapes से किसी भी ज्यामिति का इस्तेमाल कर सकता है.
बेसिक ड्रॉप शैडो लागू करने के लिए, अपने कंपोज़ेबल चेन में dropShadow() मॉडिफ़ायर जोड़ें. साथ ही, रेडियस, रंग, और स्प्रेड की जानकारी दें. ध्यान दें कि शैडो के ऊपर दिखने वाला purpleColor बैकग्राउंड, dropShadow() मॉडिफ़ायर के बाद बनाया जाता है:
@Composable fun SimpleDropShadowUsage() { Box(Modifier.fillMaxSize()) { Box( Modifier .width(300.dp) .height(300.dp) .dropShadow( shape = RoundedCornerShape(20.dp), shadow = Shadow( radius = 10.dp, spread = 6.dp, color = Color(0x40000000), offset = DpOffset(x = 4.dp, 4.dp) ) ) .align(Alignment.Center) .background( color = Color.White, shape = RoundedCornerShape(20.dp) ) ) { Text( "Drop Shadow", modifier = Modifier.align(Alignment.Center), fontSize = 32.sp ) } } }
कोड के बारे में अहम बातें
dropShadow()मॉडिफ़ायर को, अंदरूनीBoxपर लागू किया जाता है. शैडो की ये विशेषताएं हैं:- गोलाकार कोनों वाला आयत (
RoundedCornerShape(20.dp)) - ब्लर रेडियस
10.dpहै. इससे किनारों को हल्का और धुंधला किया जाता है 6.dpका स्प्रेड, जो शैडो के साइज़ को बढ़ाता है और इसे बॉक्स से बड़ा बनाता है- ऐल्फ़ा
0.5fहै, जिससे परछाई थोड़ी पारदर्शी हो जाती है
- गोलाकार कोनों वाला आयत (
- शैडो तय हो जाने के बाद, .
background()मॉडिफ़ायर लागू किया जाता है.Boxमें सफ़ेद रंग भरा गया है.- बैकग्राउंड को, शैडो के जैसे ही गोल कोनों वाले आयत के आकार में काटा जाता है.
नतीजा
इनर शैडो लागू करना
dropShadow() के उलट इफ़ेक्ट बनाने के लिए, Modifier.innerShadow() का इस्तेमाल करें. इससे ऐसा लगता है कि कोई एलिमेंट, नीचे की सतह में धंसा हुआ है या दबा हुआ है.
इनर शैडो बनाते समय, क्रम का ध्यान रखना ज़रूरी है. innerShadow() मॉडिफ़ायर, कॉन्टेंट के टॉप पर दिखता है. शैडो को दिखाने के लिए, आम तौर पर यह तरीका अपनाया जाता है:
- बैकग्राउंड कॉन्टेंट बनाएं.
- अंदर की ओर झुकी हुई इमेज बनाने के लिए,
innerShadow()मॉडिफ़ायर लागू करें.
अगर innerShadow() को बैकग्राउंड से पहले रखा जाता है, तो बैकग्राउंड को शैडो के ऊपर बनाया जाता है. इससे शैडो पूरी तरह से छिप जाती है.
यहां दिए गए उदाहरण में, RoundedCornerShape पर innerShadow() को लागू करने का तरीका दिखाया गया है:
@Composable fun SimpleInnerShadowUsage() { Box(Modifier.fillMaxSize()) { Box( Modifier .width(300.dp) .height(200.dp) .align(Alignment.Center) // note that the background needs to be defined before defining the inner shadow .background( color = Color.White, shape = RoundedCornerShape(20.dp) ) .innerShadow( shape = RoundedCornerShape(20.dp), shadow = Shadow( radius = 10.dp, spread = 2.dp, color = Color(0x40000000), offset = DpOffset(x = 6.dp, 7.dp) ) ) ) { Text( "Inner Shadow", modifier = Modifier.align(Alignment.Center), fontSize = 32.sp ) } } }
Modifier.innerShadow() का इस्तेमाल किया गया है.उपयोगकर्ता के इंटरैक्शन पर शैडो को ऐनिमेट करना
शैडो को उपयोगकर्ता के इंटरैक्शन के हिसाब से बदलने के लिए, शैडो प्रॉपर्टी को Compose के ऐनिमेशन एपीआई के साथ इंटिग्रेट किया जा सकता है. जब कोई उपयोगकर्ता किसी बटन को दबाता है, तो उदाहरण के लिए, शैडो तुरंत दिखने वाली विज़ुअल प्रतिक्रिया देने के लिए बदल सकती है.
नीचे दिए गए कोड से, शैडो के साथ "दबाया गया" इफ़ेक्ट बनाया जाता है. इससे ऐसा लगता है कि स्क्रीन पर मौजूद चीज़ को नीचे की ओर धकेला जा रहा है:
@Composable fun AnimatedColoredShadows() { SnippetsTheme { Box(Modifier.fillMaxSize()) { val interactionSource = remember { MutableInteractionSource() } val isPressed by interactionSource.collectIsPressedAsState() // Create transition with pressed state val transition = updateTransition( targetState = isPressed, label = "button_press_transition" ) fun <T> buttonPressAnimation() = tween<T>( durationMillis = 400, easing = EaseInOut ) // Animate all properties using the transition val shadowAlpha by transition.animateFloat( label = "shadow_alpha", transitionSpec = { buttonPressAnimation() } ) { pressed -> if (pressed) 0f else 1f } // ... val blueDropShadow by transition.animateColor( label = "shadow_color", transitionSpec = { buttonPressAnimation() } ) { pressed -> if (pressed) Color.Transparent else blueDropShadowColor } // ... Box( Modifier .clickable( interactionSource, indication = null ) { // ** ...... **// } .width(300.dp) .height(200.dp) .align(Alignment.Center) .dropShadow( shape = RoundedCornerShape(70.dp), shadow = Shadow( radius = 10.dp, spread = 0.dp, color = blueDropShadow, offset = DpOffset(x = 0.dp, -(2).dp), alpha = shadowAlpha ) ) .dropShadow( shape = RoundedCornerShape(70.dp), shadow = Shadow( radius = 10.dp, spread = 0.dp, color = darkBlueDropShadow, offset = DpOffset(x = 2.dp, 6.dp), alpha = shadowAlpha ) ) // note that the background needs to be defined before defining the inner shadow .background( color = Color(0xFFFFFFFF), shape = RoundedCornerShape(70.dp) ) .innerShadow( shape = RoundedCornerShape(70.dp), shadow = Shadow( radius = 8.dp, spread = 4.dp, color = innerShadowColor2, offset = DpOffset(x = 4.dp, 0.dp) ) ) .innerShadow( shape = RoundedCornerShape(70.dp), shadow = Shadow( radius = 20.dp, spread = 4.dp, color = innerShadowColor1, offset = DpOffset(x = 4.dp, 0.dp), alpha = innerShadowAlpha ) ) ) { Text( "Animated Shadows", // ... ) } } } }
कोड के बारे में अहम बातें
- यह पैरामीटर,
transition.animateColorऔरtransition.animateFloatके साथ दबाने पर ऐनिमेशन के लिए, पैरामीटर की शुरुआती और आखिरी स्थितियां तय करता है. - यह
updateTransitionका इस्तेमाल करता है और इसे चुनी गईtargetState (targetState = isPressed)के साथ उपलब्ध कराता है, ताकि यह पुष्टि की जा सके कि सभी ऐनिमेशन सिंक किए गए हैं. जब भीisPressedबदलता है, तो ट्रांज़िशन ऑब्जेक्ट, सभी चाइल्ड प्रॉपर्टी के ऐनिमेशन को उनकी मौजूदा वैल्यू से नई टारगेट वैल्यू में अपने-आप मैनेज करता है. - यह
buttonPressAnimationस्पेसिफ़िकेशन तय करता है. इससे ट्रांज़िशन के समय और ईज़िंग को कंट्रोल किया जाता है. इसमें 400 मिलीसेकंड की अवधि वालाtween(इन-बिटवीन के लिए छोटा नाम) औरEaseInOutकर्व शामिल होता है. इसका मतलब है कि ऐनिमेशन धीरे-धीरे शुरू होता है, बीच में तेज़ हो जाता है, और आखिर में धीमा हो जाता है. - यह
Boxको मॉडिफ़ायर फ़ंक्शन की चेन के साथ तय करता है. यह विज़ुअल एलिमेंट बनाने के लिए, सभी ऐनिमेशन वाली प्रॉपर्टी लागू करता है. इनमें ये शामिल हैं:- .
clickable(): यह एक ऐसा मॉडिफ़ायर है जोBoxको इंटरैक्टिव बनाता है. .dropShadow(): सबसे पहले, दो बाहरी ड्रॉप शैडो लागू की जाती हैं. इनकी रंग और ऐल्फ़ा प्रॉपर्टी, ऐनिमेशन वाली वैल्यू (blueDropShadowवगैरह) से जुड़ी होती हैं. साथ ही, इनसे शुरुआती तौर पर उभरा हुआ इफ़ेक्ट मिलता है..innerShadow(): बैकग्राउंड के ऊपर दो इनर शैडो बनाए गए हैं. इनकी प्रॉपर्टी, ऐनिमेशन वाली वैल्यू के दूसरे सेट (innerShadowColor1वगैरह) से लिंक होती हैं और इंडेंटेड लुक बनाती हैं.
- .
नतीजा
ग्रेडिएंट शैडो बनाना
शैडो सिर्फ़ सॉलिड कलर तक सीमित नहीं होती हैं. शैडो एपीआई, Brush को स्वीकार करता है. इसकी मदद से, ग्रेडिएंट शैडो बनाई जा सकती हैं.
Box( modifier = Modifier .width(240.dp) .height(200.dp) .dropShadow( shape = RoundedCornerShape(70.dp), shadow = Shadow( radius = 10.dp, spread = animatedSpread.dp, brush = Brush.sweepGradient( colors ), offset = DpOffset(x = 0.dp, y = 0.dp), alpha = animatedAlpha ) ) .clip(RoundedCornerShape(70.dp)) .background(Color(0xEDFFFFFF)), contentAlignment = Alignment.Center ) { Text( text = breathingText, color = Color.Black, style = MaterialTheme.typography.bodyLarge ) }
कोड के बारे में अहम बातें
dropShadow()बॉक्स के पीछे शैडो जोड़ता है.brush = Brush.sweepGradient(colors), शैडो को ऐसे ग्रेडिएंट से रंग देता है जो पहले से तय की गईcolorsकी सूची में घूमता है. इससे इंद्रधनुष जैसा इफ़ेक्ट बनता है.
नतीजा
ब्रश को शैडो के तौर पर इस्तेमाल करके, "ब्रीदिंग" ऐनिमेशन के साथ ग्रेडिएंट dropShadow() बनाया जा सकता है:
शैडो को एक साथ जोड़ना
अलग-अलग इफ़ेक्ट बनाने के लिए, dropShadow() और innerShadow() मॉडिफ़ायर को एक साथ इस्तेमाल किया जा सकता है. यहां दिए गए सेक्शन में, इस तकनीक का इस्तेमाल करके न्यूमॉर्फ़िक, नियोब्रूटलिस्ट, और रियलिस्टिक शैडो बनाने का तरीका बताया गया है.
न्यूमॉर्फ़िक शैडो बनाना
न्यूमॉर्फ़िक शैडो की पहचान, बैकग्राउंड से अपने-आप निकलने वाली हल्की शैडो से होती है. न्यूमॉर्फ़िक शैडो बनाने के लिए, यह तरीका अपनाएं:
- ऐसे एलिमेंट का इस्तेमाल करें जिसके रंग, उसके बैकग्राउंड के रंग से मिलते-जुलते हों.
- दो हल्की, विपरीत ड्रॉप शैडो लागू करें: एक कोने पर हल्की शैडो और दूसरे कोने पर गहरी शैडो.
नीचे दिए गए स्निपेट में, न्यूमॉर्फ़िक इफ़ेक्ट बनाने के लिए दो dropShadow() मॉडिफ़ायर का इस्तेमाल किया गया है:
@Composable fun NeumorphicRaisedButton( shape: RoundedCornerShape = RoundedCornerShape(30.dp) ) { val bgColor = Color(0xFFe0e0e0) val lightShadow = Color(0xFFFFFFFF) val darkShadow = Color(0xFFb1b1b1) val upperOffset = -10.dp val lowerOffset = 10.dp val radius = 15.dp val spread = 0.dp Box( modifier = Modifier .fillMaxSize() .background(bgColor) .wrapContentSize(Alignment.Center) .size(240.dp) .dropShadow( shape, shadow = Shadow( radius = radius, color = lightShadow, spread = spread, offset = DpOffset(upperOffset, upperOffset) ), ) .dropShadow( shape, shadow = Shadow( radius = radius, color = darkShadow, spread = spread, offset = DpOffset(lowerOffset, lowerOffset) ), ) .background(bgColor, shape) ) }
नियोब्रूटलिस्ट शैडो बनाना
नियोब्रूटलिस्ट स्टाइल में, हाई-कंट्रास्ट, ब्लॉक वाले लेआउट, चटख रंग, और मोटे बॉर्डर दिखाए जाते हैं. इस इफ़ेक्ट को बनाने के लिए, बिना धुंधलेपन वाला dropShadow() इस्तेमाल करें. साथ ही, इसे अलग ऑफ़सेट पर सेट करें. जैसा कि यहां दिए गए स्निपेट में दिखाया गया है:
@Composable fun NeoBrutalShadows() { SnippetsTheme { val dropShadowColor = Color(0xFF007AFF) val borderColor = Color(0xFFFF2D55) Box(Modifier.fillMaxSize()) { Box( Modifier .width(300.dp) .height(200.dp) .align(Alignment.Center) .dropShadow( shape = RoundedCornerShape(0.dp), shadow = Shadow( radius = 0.dp, spread = 0.dp, color = dropShadowColor, offset = DpOffset(x = 8.dp, 8.dp) ) ) .border( 8.dp, borderColor ) .background( color = Color.White, shape = RoundedCornerShape(0.dp) ) ) { Text( "Neobrutal Shadows", modifier = Modifier.align(Alignment.Center), style = MaterialTheme.typography.bodyMedium ) } } } }
असली जैसी दिखने वाली परछाइयां बनाना
असली जैसी परछाइयां, असल दुनिया में दिखने वाली परछाइयों की तरह होती हैं. ये किसी मुख्य रोशनी के स्रोत से मिलती हैं. इसलिए, इनसे सीधी परछाई और ज़्यादा फैली हुई परछाई, दोनों मिलती हैं. नीचे दिए गए स्निपेट में दिखाए गए तरीके से, अलग-अलग प्रॉपर्टी वाले dropShadow() और innerShadow() के कई इंस्टेंस को स्टैक किया जा सकता है. इससे, शैडो के असली इफ़ेक्ट फिर से बनाए जा सकते हैं:
@Composable fun RealisticShadows() { Box(Modifier.fillMaxSize()) { val dropShadowColor1 = Color(0xB3000000) val dropShadowColor2 = Color(0x66000000) val innerShadowColor1 = Color(0xCC000000) val innerShadowColor2 = Color(0xFF050505) val innerShadowColor3 = Color(0x40FFFFFF) val innerShadowColor4 = Color(0x1A050505) Box( Modifier .width(300.dp) .height(200.dp) .align(Alignment.Center) .dropShadow( shape = RoundedCornerShape(100.dp), shadow = Shadow( radius = 40.dp, spread = 0.dp, color = dropShadowColor1, offset = DpOffset(x = 2.dp, 8.dp) ) ) .dropShadow( shape = RoundedCornerShape(100.dp), shadow = Shadow( radius = 4.dp, spread = 0.dp, color = dropShadowColor2, offset = DpOffset(x = 0.dp, 4.dp) ) ) // note that the background needs to be defined before defining the inner shadow .background( color = Color.Black, shape = RoundedCornerShape(100.dp) ) // // .innerShadow( shape = RoundedCornerShape(100.dp), shadow = Shadow( radius = 12.dp, spread = 3.dp, color = innerShadowColor1, offset = DpOffset(x = 6.dp, 6.dp) ) ) .innerShadow( shape = RoundedCornerShape(100.dp), shadow = Shadow( radius = 4.dp, spread = 1.dp, color = Color.White, offset = DpOffset(x = 5.dp, 5.dp) ) ) .innerShadow( shape = RoundedCornerShape(100.dp), shadow = Shadow( radius = 12.dp, spread = 5.dp, color = innerShadowColor2, offset = DpOffset(x = (-3).dp, (-12).dp) ) ) .innerShadow( shape = RoundedCornerShape(100.dp), shadow = Shadow( radius = 3.dp, spread = 10.dp, color = innerShadowColor3, offset = DpOffset(x = 0.dp, 0.dp) ) ) .innerShadow( shape = RoundedCornerShape(100.dp), shadow = Shadow( radius = 3.dp, spread = 9.dp, color = innerShadowColor4, offset = DpOffset(x = 1.dp, 1.dp) ) ) ) { Text( "Realistic Shadows", modifier = Modifier.align(Alignment.Center), fontSize = 24.sp, color = Color.White ) } } }
कोड के बारे में अहम बातें
- अलग-अलग प्रॉपर्टी वाले दो चेन्ड
dropShadow()मॉडिफ़ायर लागू किए जाते हैं. इसके बाद, एकbackground()मॉडिफ़ायर लागू किया जाता है. - कॉम्पोनेंट के किनारे पर मेटल की रिम का इफ़ेक्ट बनाने के लिए, एक के बाद एक
innerShadow()मॉडिफ़ायर लागू किए जाते हैं.
नतीजा
ऊपर दिए गए कोड स्निपेट से यह नतीजा मिलता है: