Schatten heben die Benutzeroberfläche visuell hervor, weisen Nutzer auf Interaktivität hin und geben sofortiges Feedback zu Nutzeraktionen. Compose bietet mehrere Möglichkeiten, Schatten in Ihre App einzubinden:
Modifier.shadow()
: Erstellt einen schattenbasierten Schatten hinter einem Composable, der den Material Design-Richtlinien entspricht.Modifier.dropShadow()
: Erstellt einen anpassbaren Schatten, der hinter einem Composable angezeigt wird, sodass es erhöht erscheint.Modifier.innerShadow()
: Erstellt einen Schatten innerhalb der Ränder eines Composables, sodass es aussieht, als wäre es in die Oberfläche dahinter eingedrückt.
Modifier.shadow()
eignet sich zum Erstellen einfacher Schatten, während die Modifizierer dropShadow
und innerShadow
eine detailliertere Steuerung und Präzision beim Rendern von Schatten ermöglichen.
Auf dieser Seite wird beschrieben, wie Sie die einzelnen Modifikatoren implementieren. Dazu gehört auch, wie Sie Schatten bei Nutzerinteraktion animieren und die Modifikatoren innerShadow()
und dropShadow()
verketten, um Verlaufsschatten und neumorphe Schatten zu erstellen.
Einfache Schatten erstellen
Mit Modifier.shadow()
wird ein einfacher Schatten gemäß den Material Design-Richtlinien erstellt, der eine Lichtquelle von oben simuliert. Die Schattenstärke basiert auf einem elevation
-Wert und der Schatten wird auf die Form des Composables zugeschnitten.
@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
erstellt wurdeSchlagschatten implementieren
Mit dem Modifikator dropShadow()
können Sie einen präzisen Schatten hinter Ihren Inhalten zeichnen, wodurch das Element erhöht erscheint.
Über den Shadow
-Parameter können Sie die folgenden wichtigen Aspekte steuern:
radius
: Definiert die Weichheit und Streuung des Weichzeichners.color
: Definiert die Farbe des Tints.offset
: Positioniert die Geometrie des Schattens entlang der x- und y-Achse.spread
: Steuert die Vergrößerung oder Verkleinerung der Schattengeometrie.
Außerdem wird mit dem Parameter shape
die Gesamtform des Schattens definiert. Es kann jede Geometrie aus dem androidx.compose.foundation.shape
-Paket sowie die Material Expressive shapes verwenden.
Wenn Sie einen einfachen Schlagschatten implementieren möchten, fügen Sie den dropShadow()
-Modifikator in Ihre zusammensetzbare Kette ein und geben Sie Radius, Farbe und Streuung an. Beachten Sie, dass der purpleColor
-Hintergrund, der über dem Schatten angezeigt wird, nach dem dropShadow()
-Modifikator gezeichnet wird:
@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 ) } } }
Wichtige Punkte zum Code
- Der Modifikator
dropShadow()
wird auf die innereBox
angewendet. Der Schatten hat die folgenden Eigenschaften:- Ein abgerundetes Rechteck (
RoundedCornerShape(20.dp)
) - Ein Weichzeichnungsradius von
10.dp
, wodurch die Kanten weich und diffus werden - Ein „Spread“-Wert von
6.dp
vergrößert den Schatten und macht ihn größer als den Rahmen, der ihn wirft. - Ein Alpha von
0.5f
, wodurch der Schatten halbtransparent wird
- Ein abgerundetes Rechteck (
- Nachdem der Schatten definiert wurde,Der Modifikator „
background()
“ wird angewendet.- Die
Box
ist weiß ausgefüllt. - Der Hintergrund wird auf dieselbe abgerundete Rechteckform wie der Schatten zugeschnitten.
- Die
Ergebnis

Schatten nach innen implementieren
Wenn Sie einen umgekehrten Effekt zu dropShadow
erzielen möchten, verwenden Sie Modifier.innerShadow()
. Dadurch wird die Illusion erzeugt, dass ein Element in die darunterliegende Oberfläche eingelassen oder eingedrückt ist.
Die Reihenfolge ist beim Erstellen von inneren Schatten wichtig. Der innere Schatten wird über dem Inhalt gezeichnet. Normalerweise gehen Sie so vor:
- Zeichnen Sie die Hintergrundinhalte.
- Wenden Sie den Modifikator
innerShadow()
an, um die konkave Form zu erstellen.
Wenn innerShadow()
vor dem Hintergrund platziert wird, wird der Hintergrund über dem Schatten gezeichnet und verdeckt ihn vollständig.
Das folgende Beispiel zeigt die Anwendung von innerShadow()
auf ein 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()
auf ein Rechteck mit abgerundeten Ecken.Schatten bei Nutzerinteraktion animieren
Damit Schatten auf Nutzerinteraktionen reagieren, können Sie Schattenattribute in die Animations-APIs von Compose einbinden. Wenn ein Nutzer beispielsweise eine Schaltfläche drückt, kann sich der Schatten ändern, um sofortiges visuelles Feedback zu geben.
Mit dem folgenden Code wird ein „gedrückter“ Effekt mit einem Schatten erstellt (die Illusion, dass die Oberfläche in den Bildschirm gedrückt wird):
@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", // ... ) } } } }
Wichtige Punkte zum Code
- Deklariert die Start- und Endstatus für die Parameter, die beim Drücken animiert werden sollen, mit
transition.animateColor
undtransition.animateFloat
. - Verwendet
updateTransition
und stellt die ausgewähltetargetState (targetState = isPressed)
bereit, um zu prüfen, ob alle Animationen synchronisiert sind. Immer wenn sichisPressed
ändert, verwaltet das Übergangsobjekt automatisch die Animation aller untergeordneten Attribute von ihren aktuellen Werten zu den neuen Zielwerten. - Definiert die
buttonPressAnimation
-Spezifikation, die das Timing und die Beschleunigung des Übergangs steuert. Es wird eintween
(kurz für „in-between“) mit einer Dauer von 400 Millisekunden und einerEaseInOut
-Kurve angegeben. Das bedeutet, dass die Animation langsam beginnt, in der Mitte schneller wird und am Ende wieder langsamer wird. - Definiert ein
Box
mit einer Kette von Modifikatorfunktionen, die alle animierten Eigenschaften anwenden, um das visuelle Element zu erstellen, einschließlich der folgenden:- .
clickable()
: Ein Modifikator, der dasBox
interaktiv macht. .dropShadow()
: Zuerst werden zwei äußere Schlagschatten angewendet. Die Farb- und Alphaproperties sind mit den animierten Werten (blueDropShadow
usw.) verknüpft und sorgen für die anfängliche Erhebung..innerShadow()
: Zwei Schatten nach innen werden über dem Hintergrund gezeichnet. Ihre Eigenschaften sind mit den anderen animierten Werten (innerShadowColor1
usw.) verknüpft und sorgen für das eingerückte Erscheinungsbild.
- .
Ergebnis
Schatten mit Farbverlauf erstellen
Schatten sind nicht auf Volltonfarben beschränkt. Die Schatten-API akzeptiert ein Brush
, mit dem Sie Verlaufschatten erstellen können.
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 ) }
Wichtige Punkte zum Code
- Mit
dropShadow()
wird ein Schatten hinter dem Feld hinzugefügt. brush = Brush.sweepGradient(colors)
färbt den Schatten mit einem Farbverlauf, der eine Liste vordefiniertercolors
durchläuft und so einen regenbogenartigen Effekt erzeugt.
Ergebnis
Sie können einen Pinsel als Schatten verwenden, um einen Farbverlauf dropShadow()
mit einer „atmenden“ Animation zu erstellen:
Schatten kombinieren
Sie können die Modifikatoren dropShadow()
und innerShadow()
kombinieren und übereinanderlegen, um verschiedene Effekte zu erzielen. In den folgenden Abschnitten wird gezeigt, wie Sie mit dieser Technik neumorphe, neobrutalistische und realistische Schatten erzeugen.
Neumorphe Schatten erstellen
Neumorphe Schatten zeichnen sich durch ein weiches Erscheinungsbild aus, das sich organisch aus dem Hintergrund ergibt. So erstellen Sie neumorphe Schatten:
- Verwenden Sie ein Element, das dieselben Farben wie sein Hintergrund hat.
- Wenden Sie zwei schwache, gegenüberliegende Schlagschatten an: einen hellen Schatten in einer Ecke und einen dunklen Schatten in der gegenüberliegenden Ecke.
Im folgenden Snippet werden zwei dropShadow()
-Modifikatoren geschichtet, um den neumorphen Effekt zu erzielen:
@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) ) }

Neobrutalistische Schatten erstellen
Der neobrutalistische Stil zeichnet sich durch kontrastreiche, blockartige Layouts, lebendige Farben und dicke Ränder aus. Verwenden Sie für diesen Effekt einen dropShadow()
ohne Unschärfe und mit einem deutlichen Offset, wie im folgenden Snippet gezeigt:
@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 ) } } } }

Realistische Schatten erstellen
Realistische Schatten ähneln Schatten in der physischen Welt. Sie werden von einer primären Lichtquelle beleuchtet, was zu einem direkten und einem diffusen Schatten führt. Sie können mehrere dropShadow()
- und innerShadow()
-Instanzen mit unterschiedlichen Eigenschaften stapeln, um realistische Schatteneffekte zu erzielen, wie im folgenden Snippet gezeigt:
@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 ) } } }
Wichtige Punkte zum Code
- Es werden zwei verkettete
dropShadow()
-Modifikatoren mit unterschiedlichen Eigenschaften angewendet, gefolgt von einembackground
-Modifikator. - Verkettete
innerShadow()
-Modifizierer werden angewendet, um den metallischen Rändereffekt um die Kante der Komponente zu erzeugen.
Ergebnis
Das vorherige Code-Snippet erzeugt Folgendes:
