As sombras elevam visualmente a interface, indicam interatividade aos usuários e fornecem feedback imediato sobre as ações deles. O Compose oferece várias maneiras de incorporar sombras ao app:
Modifier.shadow()
: cria uma sombra com base em elevação atrás de um elemento combinável que está de acordo com as diretrizes do Material Design.Modifier.dropShadow()
: cria uma sombra personalizável que aparece atrás de um elemento combinável, fazendo com que ele pareça elevado.Modifier.innerShadow()
: cria uma sombra dentro das bordas de um elemento combinável, fazendo com que ele pareça pressionado na superfície atrás dele.
Modifier.shadow()
é adequado para criar sombras básicas, enquanto os modificadores dropShadow
e innerShadow
oferecem mais controle e precisão sobre a renderização de sombras.
Esta página descreve como implementar cada um desses modificadores, incluindo como animar sombras na interação do usuário e como encadear os modificadores innerShadow()
e dropShadow()
para criar sombras gradientes, sombras neomórficas e muito mais.
Criar sombras básicas
Modifier.shadow()
cria uma sombra básica seguindo as diretrizes do Material Design (link em inglês) que simula uma fonte de luz de cima. A profundidade
da sombra é baseada em um valor elevation
, e a sombra projetada é cortada na
forma do elemento combinável.
@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
.Implementar sombras projetadas
Use o modificador dropShadow()
para desenhar uma sombra precisa atrás do
conteúdo, o que faz com que o elemento pareça elevado.
É possível controlar os seguintes aspectos principais com o parâmetro Shadow
:
radius
: define a suavidade e a difusão do desfoque.color
: define a cor da tonalidade.offset
: posiciona a geometria da sombra ao longo dos eixos x e y.spread
: controla a expansão ou contração da geometria da sombra.
Além disso, o parâmetro shape
define a forma geral da sombra. Ele pode usar qualquer geometria do pacote androidx.compose.foundation.shape
, bem como as formas expressivas do Material.
Para implementar uma sombra projetada básica, adicione o modificador dropShadow()
à sua
cadeia de elementos combináveis, fornecendo o raio, a cor e a extensão. O plano de fundo purpleColor
que aparece acima da sombra é desenhado depois do modificador 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 ) } } }
Pontos principais sobre o código
- O modificador
dropShadow()
é aplicado aoBox
interno. A sombra tem as seguintes características:- Uma forma de retângulo arredondado (
RoundedCornerShape(20.dp)
) - Um raio de desfoque de
10.dp
, deixando as bordas suaves e difusas - Uma propagação de
6.dp
, que aumenta o tamanho da sombra e a torna maior do que a caixa que a projeta - Um alfa de
0.5f
, tornando a sombra semitransparente
- Uma forma de retângulo arredondado (
- Depois que a sombra é definida, o .O modificador
background()
é aplicado.- O
Box
é preenchido com uma cor branca. - O plano de fundo é cortado no mesmo formato de retângulo arredondado da sombra.
- O
Resultado

Implementar sombras internas
Para criar um efeito inverso ao dropShadow
, use Modifier.innerShadow()
,
que cria a ilusão de que um elemento está embutido ou pressionado na
superfície subjacente.
A ordem é importante ao criar sombras internas. A sombra interna é desenhada na parte de cima do conteúdo. Portanto, geralmente é necessário fazer o seguinte:
- Desenhe o conteúdo em segundo plano.
- Aplique o modificador
innerShadow()
para criar a aparência côncava.
Se o innerShadow()
for colocado antes do plano de fundo, ele será desenhado
sobre a sombra, ocultando-a completamente.
O exemplo a seguir mostra uma aplicação de innerShadow()
em um
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()
em um retângulo de canto arredondado.Animar sombras na interação do usuário
Para fazer com que as sombras respondam às interações do usuário, integre propriedades de sombra com as APIs de animação do Compose. Quando um usuário pressiona um botão, por exemplo, a sombra pode mudar para fornecer feedback visual instantâneo.
O código a seguir cria um efeito "pressionado" com uma sombra (a ilusão de que a superfície está sendo empurrada para baixo na tela):
@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", // ... ) } } } }
Pontos principais sobre o código
- Declara os estados inicial e final dos parâmetros a serem animados ao pressionar
com
transition.animateColor
etransition.animateFloat
. - Usa
updateTransition
e fornece otargetState (targetState = isPressed)
escolhido para verificar se todas as animações estão sincronizadas. Sempre queisPressed
muda, o objeto de transição gerencia automaticamente a animação de todas as propriedades filhas dos valores atuais para os novos valores de destino. - Define a especificação
buttonPressAnimation
, que controla o tempo e a facilidade da transição. Ele especifica umtween
(abreviação de in-between) com uma duração de 400 milissegundos e uma curvaEaseInOut
, o que significa que a animação começa devagar, acelera no meio e diminui no final. - Define um
Box
com uma cadeia de funções modificadoras que aplicam todas as propriedades animadas para criar o elemento visual, incluindo o seguinte:- .
clickable()
: um modificador que torna oBox
interativo. .dropShadow()
: duas sombras projetadas externas são aplicadas primeiro. As propriedades de cor e alfa são vinculadas aos valores animados (blueDropShadow
etc.) e criam a aparência elevada inicial..innerShadow()
: duas sombras internas são desenhadas sobre o plano de fundo. As propriedades deles estão vinculadas ao outro conjunto de valores animados (innerShadowColor1
etc.) e criam a aparência recuada.
- .
Resultado
Criar sombras gradientes
As sombras não estão limitadas a cores sólidas. A API Shadow aceita um Brush
, que
permite criar sombras gradientes.
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 ) }
Pontos principais sobre o código
dropShadow()
adiciona uma sombra atrás da caixa.brush = Brush.sweepGradient(colors)
colore a sombra com um gradiente que gira por uma lista decolors
predefinidos, criando um efeito semelhante a um arco-íris.
Resultado
É possível usar um pincel como uma sombra para criar um gradiente dropShadow()
com uma animação de "respiração":
Combinar sombras
Você pode combinar e criar camadas com os modificadores dropShadow()
e innerShadow()
para criar vários efeitos. As seções a seguir mostram como produzir sombras neomórficas, neobrutalistas e realistas com essa técnica.
Criar sombras neomórficas
As sombras neomórficas têm uma aparência suave que surge organicamente do plano de fundo. Para criar sombras neomórficas, faça o seguinte:
- Use um elemento que tenha as mesmas cores do plano de fundo.
- Aplique duas sombras projetadas leves e opostas: uma clara em um canto e uma escura no canto oposto.
O snippet a seguir sobrepõe dois modificadores dropShadow()
para criar o
efeito neomórfico:
@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) ) }

Criar sombras neobrutalistas
O estilo neobrutalista mostra layouts em blocos de alto contraste, cores vibrantes e bordas grossas. Para criar esse efeito, use um dropShadow()
com desfoque zero
e um deslocamento distinto, conforme mostrado no snippet a seguir:
@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 ) } } } }

Criar sombras realistas
As sombras realistas imitam as sombras do mundo físico. Elas parecem iluminadas por uma fonte de luz primária, resultando em uma sombra direta e outra mais difusa. É possível empilhar várias instâncias dropShadow()
e innerShadow()
com propriedades diferentes para recriar efeitos de sombra realistas, conforme mostrado no snippet a seguir:
@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 ) } } }
Pontos principais sobre o código
- Dois modificadores
dropShadow()
encadeados com propriedades distintas são aplicados, seguidos por um modificadorbackground
. - Modificadores
innerShadow()
encadeados são aplicados para criar o efeito de borda metálica ao redor da borda do componente.
Resultado
O snippet de código anterior produz o seguinte:
