سایهها از نظر بصری رابط کاربری شما را ارتقا میدهند، تعامل را به کاربران نشان میدهند و بازخورد فوری در مورد اقدامات کاربر ارائه میدهند. 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
: میزان نرمی و پراکندگی محوشدگی (blur) شما را تعریف میکند. -
color
: رنگ ته رنگ را تعریف میکند. -
offset
: هندسه سایه را در امتداد محورهای x و y قرار میدهد. -
spread
: انبساط یا انقباض هندسه سایه را کنترل میکند.
علاوه بر این، پارامتر shape
شکل کلی سایه را تعریف میکند. میتواند از هر هندسهای از بسته androidx.compose.foundation.shape
و همچنین اشکال Material Expressive استفاده کند.
برای پیادهسازی یک سایهی ساده، اصلاحکنندهی 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()
قبل از پسزمینه قرار گیرد، پسزمینه روی سایه کشیده میشود و آن را کاملاً پنهان میکند.
مثال زیر کاربرد تابع innerShadow()
را روی یک RoundedCornerShape
نشان میدهد:
@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()
روی یک مستطیل با گوشههای گرد.سایهها را در تعامل کاربر متحرک کنید
برای اینکه سایههای شما به تعاملات کاربر واکنش نشان دهند، میتوانید ویژگیهای سایه را با APIهای انیمیشن 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
تغییر کند، شیء transition به طور خودکار انیمیشن همه ویژگیهای فرزند را از مقادیر فعلی آنها به مقادیر هدف جدید مدیریت میکند. - مشخصات
buttonPressAnimation
را تعریف میکند که زمانبندی و کاهش سرعت انتقال را کنترل میکند. این ویژگی یکtween
(مخفف in-between) با مدت زمان ۴۰۰ میلیثانیه و یک منحنیEaseInOut
مشخص میکند، به این معنی که انیمیشن با سرعت کم شروع میشود، در میانه سرعت میگیرد و در پایان سرعتش کم میشود. - یک
Box
با زنجیرهای از توابع اصلاحکننده تعریف میکند که تمام ویژگیهای متحرک را برای ایجاد عنصر بصری اعمال میکنند، از جمله موارد زیر:-
clickable()
: یک اصلاحکننده که باعث میشودBox
تعاملی باشد. -
.dropShadow()
: ابتدا دو سایه بیرونی اعمال میشوند. ویژگیهای رنگ و آلفای آنها به مقادیر متحرک (blueDropShadow
و غیره) پیوند داده میشوند و ظاهر برجسته اولیه را ایجاد میکنند. -
.innerShadow()
: دو سایه داخلی روی پسزمینه رسم میشوند. ویژگیهای آنها به مجموعه دیگری از مقادیر متحرک (innerShadowColor1
و غیره) مرتبط هستند و ظاهر تورفتگی ایجاد میکنند.
-
نتیجه
ایجاد سایههای گرادیان
سایهها محدود به رنگهای یکدست نیستند. API سایه یک 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 ) } } }
نکات کلیدی در مورد کد
- دو اصلاحکنندهی (modifier
dropShadow()
زنجیرهای با ویژگیهای متمایز اعمال میشوند و پس از آنها یک اصلاحکنندهی (modifierbackground()
قرار میگیرد. - اصلاحکنندههای
innerShadow()
به صورت زنجیرهای برای ایجاد جلوهی حاشیهی فلزی در اطراف لبهی قطعه اعمال میشوند.
نتیجه
قطعه کد قبلی نتیجه زیر را تولید میکند:
