سایهها بهصورت دیداری میانای کاربر را ارتقا میدهند، تعاملپذیری را به کاربران نشان میدهند، و بازخورد فوری درباره کنشهای کاربر ارائه میدهند. Compose چندین روش برای گنجاندن سایه در برنامه ارائه میدهد:
Modifier.shadow(): سایهای مبتنی بر ارتفاع در پشت یک composable ایجاد میکند که با دستورالعملهای Material Design مطابقت دارد.Modifier.dropShadow(): سایهای قابلسفارشیسازی ایجاد میکند که پشت یک composable ظاهر میشود و آن را برجسته نشان میدهد.Modifier.innerShadow(): سایهای در داخل مرزهای یک composable ایجاد میکند و باعث میشود که بهنظر برسد به سطح پشت آن فشار داده شده است.
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 استفاده کند.
برای پیادهسازی سایه ساده، اصلاحکننده 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() در مستطیل با گوشه گرد.پویانمایی سایهها در تعامل کاربر
برای اینکه سایههایتان به تعاملات کاربر پاسخ دهند، میتوانید ویژگیهای سایه را با میاناهای برنامهسازی کاربردی پویانمایی 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را تعریف میکند که زمانبندی و کاهش سرعت گذار را کنترل میکند. این ویژگی یکtween(کوتهنوشت in-between) با مدت ۴۰۰ میلیثانیه و منحنیEaseInOutرا مشخص میکند، که یعنی پویانمایی بهآرامی شروع میشود، در وسط سرعت میگیرد، و در پایان کند میشود. - یک
Boxرا با زنجیرهای از توابع اصلاحکننده تعریف میکند که همه ویژگیهای پویانماییشده را برای ایجاد عنصر بصری اعمال میکنند، ازجمله موارد زیر:- .
clickable(): اصلاحگری کهBoxرا تعاملی میکند. .dropShadow(): ابتدا دو سایه بیرونی اعمال میشود. ویژگیهای رنگ و آلفای آنها به مقادیر پویانماییشده (blueDropShadowو غیره) پیوند داده شده است و ظاهر برجسته اولیه را ایجاد میکند.-
.innerShadow(): دو سایه داخلی در بالای پسزمینه کشیده شده است. خصوصیات آنها به مجموعه دیگری از مقادیر پویانماییشده پیوند داده شده است (innerShadowColor1و غیره) و ظاهر تورفته را ایجاد میکند.
- .
نتیجه
ایجاد سایههای گرادیان
سایهها محدود به رنگهای یکدست نیستند. shadow 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 ) } } }
نکات کلیدی درباره کد
- دو اصلاحگر زنجیرهای
dropShadow()با ویژگیهای متمایز اعمال شدهاند، و بهدنبال آن یک اصلاحگرbackground()آمده است. - اصلاحکنندههای زنجیرهای
innerShadow()برای ایجاد جلوه لبه فلزی در اطراف لبه مؤلفه اعمال میشوند.
نتیجه
تکهکد قبلی نتیجه زیر را تولید میکند: