Bayangan secara visual meningkatkan kualitas UI Anda, menunjukkan interaktivitas kepada pengguna, dan memberikan masukan langsung tentang tindakan pengguna. Compose menyediakan beberapa cara untuk menyertakan bayangan ke dalam aplikasi Anda:
Modifier.shadow()
: Membuat bayangan berbasis elevasi di belakang composable yang sesuai dengan pedoman Desain Material.Modifier.dropShadow()
: Membuat bayangan yang dapat disesuaikan yang muncul di belakang composable, sehingga membuatnya tampak lebih tinggi.Modifier.innerShadow()
: Membuat bayangan di dalam batas composable, sehingga tampak ditekan ke permukaan di belakangnya.
Modifier.shadow()
cocok untuk membuat bayangan dasar, sedangkan pengubah
dropShadow
dan innerShadow
menawarkan kontrol dan presisi yang lebih terperinci atas rendering bayangan.
Halaman ini menjelaskan cara menerapkan setiap pengubah ini, termasuk cara
menganimasikan bayangan saat interaksi pengguna dan cara mengaitkan pengubah
innerShadow()
dan dropShadow()
untuk
membuat bayangan gradien,
bayangan neomorfik, dan lainnya.
Membuat bayangan dasar
Modifier.shadow()
membuat bayangan dasar yang mengikuti panduan Desain Material yang menyimulasikan sumber cahaya dari atas. Kedalaman
bayangan didasarkan pada nilai elevation
, dan bayangan yang dilemparkan dipangkas ke
bentuk composable.
@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
.Menerapkan drop shadow
Gunakan pengubah dropShadow()
untuk menggambar bayangan yang akurat di belakang
konten Anda, yang membuat elemen tampak lebih tinggi.
Anda dapat mengontrol aspek utama berikut melalui parameter Shadow
:
radius
: Menentukan kelembutan dan difusi keburaman Anda.color
: Menentukan warna nuansa.offset
: Memosisikan geometri bayangan di sepanjang sumbu x dan y.spread
: Mengontrol perluasan atau kontraksi geometri bayangan.
Selain itu, parameter shape
menentukan bentuk keseluruhan bayangan. Anda dapat menggunakan geometri apa pun dari paket androidx.compose.foundation.shape
, serta bentuk Ekspresif Material.
Untuk menerapkan bayangan jatuh dasar, tambahkan pengubah dropShadow()
ke rantai composable Anda, dengan memberikan radius, warna, dan penyebaran. Perhatikan bahwa latar belakang
purpleColor
yang muncul di atas bayangan digambar setelah pengubah
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 ) } } }
Poin penting tentang kode
- Pengubah
dropShadow()
diterapkan keBox
dalam. Bayangan memiliki karakteristik berikut:- Bentuk persegi panjang bulat (
RoundedCornerShape(20.dp)
) - Radius blur
10.dp
, membuat tepi menjadi lembut dan menyebar - Penyebaran
6.dp
, yang memperluas ukuran bayangan dan membuatnya lebih besar daripada kotak yang memancarkannya - Alfa
0.5f
, membuat bayangan semi-transparan
- Bentuk persegi panjang bulat (
- Setelah bayangan ditentukan, .Pengubah
background()
diterapkan.Box
diisi dengan warna putih.- Latar belakang dipangkas ke bentuk persegi panjang melengkung yang sama dengan bayangan.
Hasil

Menerapkan bayangan dalam
Untuk membuat efek terbalik pada dropShadow
, gunakan Modifier.innerShadow()
,
yang menciptakan ilusi bahwa elemen tersembunyi atau ditekan ke dalam
permukaan di bawahnya.
Urutan penting saat membuat bayangan dalam. Bayangan dalam digambar di atas konten, jadi biasanya Anda harus melakukan hal berikut:
- Gambar konten latar belakang Anda.
- Terapkan pengubah
innerShadow()
untuk membuat tampilan cekung.
Jika innerShadow()
ditempatkan sebelum latar belakang, latar belakang akan digambar di atas bayangan, sehingga menyembunyikannya sepenuhnya.
Contoh berikut menunjukkan penerapan innerShadow()
pada
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()
pada persegi panjang dengan sudut membulat.Menganimasikan bayangan saat interaksi pengguna
Untuk membuat bayangan merespons interaksi pengguna, Anda dapat mengintegrasikan properti bayangan dengan API animasi Compose. Saat pengguna menekan tombol, misalnya, bayangan dapat berubah untuk memberikan masukan visual secara instan.
Kode berikut membuat efek "ditekan" dengan bayangan (ilusi bahwa permukaan didorong ke bawah ke dalam layar):
@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", // ... ) } } } }
Poin penting tentang kode
- Mendeklarasikan status awal dan akhir untuk parameter yang akan dianimasikan saat ditekan
dengan
transition.animateColor
dantransition.animateFloat
. - Menggunakan
updateTransition
dan menyediakannya dengantargetState (targetState = isPressed)
yang dipilih untuk memverifikasi semua animasi disinkronkan. Setiap kaliisPressed
berubah, objek transisi akan otomatis mengelola animasi semua properti turunan dari nilai saat ini ke nilai target baru. - Menentukan spesifikasi
buttonPressAnimation
, yang mengontrol pengaturan waktu dan kemudahan transisi. Bagian ini menentukantween
(singkatan dari di antara) dengan durasi 400 milidetik dan kurvaEaseInOut
, yang berarti animasi dimulai dengan lambat, dipercepat di tengah, dan diperlambat di akhir. - Menentukan
Box
dengan rangkaian fungsi pengubah yang menerapkan semua properti animasi untuk membuat elemen visual, termasuk berikut ini:- .
clickable()
: Pengubah yang membuatBox
menjadi interaktif. .dropShadow()
: Dua drop shadow luar diterapkan terlebih dahulu. Properti warna dan alfanya ditautkan ke nilai animasi (blueDropShadow
, dll.) dan menciptakan tampilan timbul awal..innerShadow()
: Dua bayangan dalam digambar di atas latar belakang. Propertinya ditautkan ke kumpulan nilai animasi lainnya (innerShadowColor1
, dll.) dan membuat tampilan yang menjorok.
- .
Hasil
Membuat bayangan gradien
Bayangan tidak terbatas pada warna solid. Shadow API menerima Brush
, yang
memungkinkan Anda membuat bayangan gradien.
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 ) }
Poin penting tentang kode
dropShadow()
menambahkan bayangan di belakang kotak.brush = Brush.sweepGradient(colors)
mewarnai bayangan dengan gradien yang berputar melalui daftarcolors
yang telah ditentukan, sehingga menciptakan efek seperti pelangi.
Hasil
Anda dapat menggunakan kuas sebagai bayangan untuk membuat gradien dropShadow()
dengan animasi "bernafas":
Menggabungkan bayangan
Anda dapat menggabungkan dan menyusun pengubah dropShadow()
dan innerShadow()
untuk
membuat berbagai efek. Bagian berikut menunjukkan cara menghasilkan bayangan neumorfik, neobrutalis, dan realistis dengan teknik ini.
Membuat bayangan neumorfik
Bayangan neumorfik dicirikan oleh tampilan lembut yang muncul secara organik dari latar belakang. Untuk membuat bayangan neumorfik, lakukan hal berikut:
- Gunakan elemen yang memiliki warna yang sama dengan latar belakangnya.
- Terapkan dua drop shadow berlawanan yang samar: shadow terang di satu sudut, dan shadow gelap di sudut yang berlawanan.
Cuplikan berikut melapisi dua pengubah dropShadow()
untuk membuat efek
neumorfik:
@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) ) }

Membuat bayangan neobrutalis
Gaya neobrutalis menampilkan tata letak kotak-kotak dengan kontras tinggi, warna cerah, dan batas tebal. Untuk membuat efek ini, gunakan dropShadow()
dengan blur nol
dan offset yang berbeda, seperti yang ditunjukkan dalam cuplikan berikut:
@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 ) } } } }

Membuat bayangan yang realistis
Bayangan realistis meniru bayangan di dunia fisik—bayangan tampak diterangi oleh sumber cahaya utama, sehingga menghasilkan bayangan langsung dan bayangan yang lebih menyebar. Anda dapat menumpuk beberapa instance dropShadow()
dan innerShadow()
dengan
properti yang berbeda untuk membuat ulang efek bayangan yang realistis, seperti yang ditunjukkan dalam
cuplikan berikut:
@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 ) } } }
Poin penting tentang kode
- Dua pengubah
dropShadow()
yang dirangkai dengan properti berbeda diterapkan, diikuti dengan pengubahbackground
. - Pengubah
innerShadow()
yang dirangkai diterapkan untuk membentuk efek bingkai logam di sekitar tepi komponen.
Hasil
Cuplikan kode sebelumnya menghasilkan hal berikut:
