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 höhenbasierten Schatten hinter einem Compose-Element, der den Material Design-Richtlinien entspricht.Modifier.dropShadow(): Erstellt einen anpassbaren Schatten, der hinter einer komponierbaren Funktion angezeigt wird, sodass sie erhöht erscheint.Modifier.innerShadow(): Erstellt einen Schatten innerhalb der Grenzen einer komponierbaren Funktion, sodass sie so aussieht, als wäre sie in die Oberfläche dahinter gedrückt.
Modifier.shadow() eignet sich für einfache Schatten, während die Modifikatoren dropShadow() und innerShadow() eine genauere Steuerung und Präzision beim Rendern von Schatten bieten.
Auf dieser Seite wird beschrieben, wie Sie die einzelnen Modifikatoren implementieren. Dazu gehört auch, wie Sie Schatten bei Nutzerinteraktionen animieren und wie Sie die Modifikatoren innerShadow() und dropShadow() verketten, um Schatten mit Farbverlauf, neumorphe Schatten und mehr zu erstellen.
Einfache Schatten erstellen
Modifier.shadow() erstellt einen einfachen Schatten gemäß den Material Design-Richtlinien, der eine Lichtquelle von oben simuliert. Die Schattentiefe basiert auf einem elevation-Wert und der Schattenwurf wird auf die Form des Composeables 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 wurde.Schlagschatten implementieren
Verwenden Sie den Modifikator dropShadow(), um einen genauen Schatten hinter Ihren Inhalten zu zeichnen, damit das Element erhöht erscheint.
Über den Parameter Shadow können Sie die folgenden wichtigen Aspekte steuern:
radius: Definiert die Weichheit und Diffusion der Unschärfe.color: Definiert die Farbe der Tönung.offset: Positioniert die Geometrie des Schattens entlang der x- und y-Achse.spread: Steuert die Ausdehnung oder Kontraktion der Schattengeometrie.
Außerdem wird mit dem Parameter shape die Gesamtform des Schattens definiert. Sie können jede Geometrie aus dem androidx.compose.foundation.shape-Paket sowie die Material Expressive-Formen verwenden.
Wenn Sie einen einfachen Schlagschatten implementieren möchten, fügen Sie der zusammensetzbaren Kette den Modifikator dropShadow() hinzu und geben Sie Radius, Farbe und Streuung an. Beachte, dass der Hintergrund purpleColor, der über dem Schatten angezeigt wird, nach dem Modifikator dropShadow() 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 das innereBoxangewendet. Der Schatten hat folgende Eigenschaften:- Ein abgerundetes Rechteck (
RoundedCornerShape(20.dp)) - Einen Unschärferadius von
10.dp, wodurch die Ränder weich und diffus werden - Eine Streuung von
6.dp, die die Größe des Schattens vergrößert und ihn größer als das Element macht, das ihn wirft - Ein Alphawert von
0.5f, wodurch der Schatten halbtransparent wird
- Ein abgerundetes Rechteck (
- Nachdem der Schatten definiert wurde, wird die .Der Modifikator „
background()“ wird angewendet.- Das
Boxist weiß ausgefüllt. - Der Hintergrund wird auf dieselbe abgerundete Rechteckform wie der Schatten zugeschnitten.
- Das
Ergebnis

Schatten nach innen implementieren
Wenn Sie einen umgekehrten Effekt zu dropShadow() erstellen möchten, verwenden Sie Modifier.innerShadow(). Dadurch entsteht die Illusion, dass ein Element in die darunter liegende Oberfläche eingelassen oder gedrückt ist.
Die Reihenfolge ist beim Erstellen von inneren Schatten wichtig. Der Modifikator innerShadow() wird über dem Inhalt gezeichnet. Damit der Schatten sichtbar ist, führen Sie normalerweise die folgenden Schritte aus:
- Zeichnen Sie den Hintergrundinhalt.
- Wenden Sie den Modifikator
innerShadow()an, um die konkave Form zu erstellen.
Wenn der 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 eine 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
Wenn Sie möchten, dass Ihre Schatten auf Nutzerinteraktionen reagieren, können Sie Schatteneigenschaften in die Animation APIs von Compose einbinden. Wenn ein Nutzer beispielsweise auf eine Schaltfläche drückt, kann sich der Schatten ändern, um sofortiges visuelles Feedback zu geben.
Mit dem folgenden Code wird ein „Gedrückt“-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 Endzustände für die Parameter, die beim Drücken mit
transition.animateColorundtransition.animateFloatanimiert werden sollen. - Verwendet
updateTransitionund stellt die ausgewähltetargetState (targetState = isPressed)bereit, um zu prüfen, ob alle Animationen synchronisiert sind. 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 beschleunigt und am Ende langsamer wird. - Definiert ein
Boxmit einer Kette von Modifikatorfunktionen, die alle animierten Attribute anwenden, um das visuelle Element zu erstellen, einschließlich der folgenden:- .
clickable(): Ein Modifikator, der dieBoxinteraktiv macht. .dropShadow(): Zuerst werden zwei äußere Schlagschatten angewendet. Ihre Farb- und Alpha-Eigenschaften sind mit den animierten Werten (blueDropShadowusw.) verknüpft und erzeugen die anfängliche erhöhte Darstellung..innerShadow(): Zwei Schatten nach innen werden über dem Hintergrund gezeichnet. Ihre Eigenschaften sind mit dem anderen Satz animierter Werte (innerShadowColor1usw.) verknüpft und erzeugen das eingerückte Erscheinungsbild.
- .
Ergebnis
Schatten mit Farbverlauf erstellen
Schatten sind nicht auf Volltonfarben beschränkt. Die Shadow API akzeptiert einen Brush, mit dem Sie Schatten mit Farbverlauf 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
dropShadow()fügt einen Schatten hinter dem Feld hinzu.brush = Brush.sweepGradient(colors)färbt den Schatten mit einem Farbverlauf ein, der durch eine Liste vordefiniertercolorsrotiert und so einen regenbogenähnlichen 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 der Hintergrund hat.
- Wenden Sie zwei schwache, entgegengesetzte Schlagschatten an: einen hellen Schatten in einer Ecke und einen dunklen Schatten in der gegenüberliegenden Ecke.
Im folgenden Snippet werden zwei dropShadow()-Modifikatoren übereinandergelegt, 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, leuchtende Farben und dicke Ränder aus. Verwenden Sie dazu einen dropShadow() ohne Unschärfe und mit einem deutlichen Versatz, 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 ahmen Schatten in der physischen Welt nach. Sie werden von einer primären Lichtquelle beleuchtet, was sowohl zu einem direkten als auch zu einem diffuseren Schatten führt. Sie können mehrere dropShadow()- und innerShadow()-Instanzen mit unterschiedlichen Attributen stapeln, um realistische Schatteneffekte zu erzeugen, 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()-Modifikatoren werden angewendet, um den Metalleffekt am Rand der Komponente zu erzeugen.
Ergebnis
Das vorherige Code-Snippet erzeugt Folgendes: