Тени визуально улучшают ваш пользовательский интерфейс, указывают на интерактивность и обеспечивают мгновенную обратную связь на действия пользователя. Compose предлагает несколько способов добавить тени в ваше приложение:
-  Modifier.shadow(): создает тень на основе высоты позади компонуемого объекта, соответствующую принципам Material Design.
-  Modifier.dropShadow(): создает настраиваемую тень, которая появляется позади компонуемого объекта, делая его визуально приподнятым.
-  Modifier.innerShadow(): Создает тень внутри границ компонуемого объекта, заставляя его казаться вдавленным в поверхность позади него.
 Modifier.shadow() подходит для создания базовых теней, тогда как модификаторы dropShadow() и innerShadow() обеспечивают более детальный контроль и точность при рендеринге теней.
 На этой странице описывается, как реализовать каждый из этих модификаторов, включая анимацию теней при взаимодействии с пользователем и объединение модификаторов innerShadow() и dropShadow() для создания градиентных теней , неоморфных теней и многого другого.
Создайте базовые тени
 Modifier.shadow() создаёт базовую тень, следуя принципам Material Design , имитирующую источник света сверху. Глубина тени определяется значением 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 ) } } }
Ключевые моменты кода
-  К внутреннему Boxприменяется модификаторdropShadow(). Тень имеет следующие характеристики:-  Форма скругленного прямоугольника ( 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объект перехода автоматически управляет анимацией всех дочерних свойств с их текущих значений до новых целевых значений.
-  Определяет спецификацию buttonPressAnimation, которая управляет временем и плавностью перехода. Она задаётtween(сокращение от in-between) длительностью 400 миллисекунд и кривую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 ) } } }
Ключевые моменты кода
-  Применяются два связанных модификатора dropShadow()с различными свойствами, за которыми следует модификаторbackground().
-  Для создания эффекта металлического ободка по краю компонента применяются цепочка модификаторов innerShadow().
Результат
Предыдущий фрагмент кода выводит следующее:

