Oluşturma modunda gölge ekleme

Gölgeler, kullanıcı arayüzünüzü görsel olarak geliştirir, kullanıcılara etkileşimli olduğunu gösterir ve kullanıcı işlemlerine anında geri bildirim sağlar. Compose, uygulamanıza gölge eklemenin birkaç yolunu sunar:

  • Modifier.shadow(): Materyal Tasarım yönergelerine uygun bir composable'ın arkasında yüksekliğe dayalı bir gölge oluşturur.
  • Modifier.dropShadow(): Bir composable'ın arkasında görünen ve composable'ın yükseltilmiş görünmesini sağlayan özelleştirilebilir bir gölge oluşturur.
  • Modifier.innerShadow(): Bir composable'ın sınırları içinde gölge oluşturarak arkasındaki yüzeye bastırılmış gibi görünmesini sağlar.

Modifier.shadow(), temel gölgeler oluşturmak için uygundur. dropShadow() ve innerShadow() değiştiricileri ise gölge oluşturma üzerinde daha ayrıntılı kontrol ve hassasiyet sağlar.

Bu sayfada, kullanıcı etkileşimi üzerine gölgelere animasyon ekleme ve gradyan gölgeler, neumorphic gölgeler ve daha fazlasını oluşturmak için innerShadow() ve dropShadow() değiştiricilerini zincirleme dahil olmak üzere bu değiştiricilerin her birinin nasıl uygulanacağı açıklanmaktadır.

Temel gölgeler oluşturma

Modifier.shadow(), Materyal Tasarım yönergelerine uygun olarak, yukarıdan gelen bir ışık kaynağını simüle eden temel bir gölge oluşturur. Gölge derinliği elevation değerine göre belirlenir ve gölge, composable'ın şekline göre kırpılır.

@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)
        )
    }
}

Beyaz dikdörtgen şeklin etrafında gri bir gölge.
Şekil 1. Modifier.shadow() ile oluşturulan, yüksekliğe dayalı bir gölge.

Gölge uygulama

İçeriğinizin arkasında doğru bir gölge çizmek için dropShadow() değiştiricisini kullanın. Bu, öğenin yükseltilmiş görünmesini sağlar.

Shadow parametresi aracılığıyla aşağıdaki temel özellikleri kontrol edebilirsiniz:

  • radius: Bulanıklığınızın yumuşaklığını ve dağılımını tanımlar.
  • color: Tonun rengini tanımlar.
  • offset: Gölgenin geometrisini x ve y eksenleri boyunca konumlandırır.
  • spread: Gölge geometrisinin genişlemesini veya daralmasını kontrol eder.

Ayrıca shape parametresi, gölgenin genel şeklini tanımlar. androidx.compose.foundation.shape paketindeki tüm geometrilerin yanı sıra Material Expressive şekillerini de kullanabilir.

Temel bir gölge uygulamak için yarıçap, renk ve yayılma değerlerini sağlayarak composable zincirinize dropShadow() değiştiricisini ekleyin. Gölgenin üstünde görünen purpleColor arka planının, dropShadow() değiştiricisinden sonra çizildiğine dikkat edin:

@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
            )
        }
    }
}

Kodla ilgili önemli noktalar

  • dropShadow() değiştiricisi, içteki Box öğesine uygulanır. Gölge aşağıdaki özelliklere sahiptir:
    • Köşeleri yuvarlatılmış dikdörtgen şekli (RoundedCornerShape(20.dp))
    • 10.dp bulanıklık yarıçapı, kenarları yumuşak ve dağınık hale getirir.
    • Gölgenin boyutunu genişleten ve gölgeyi oluşturan kutudan daha büyük hale getiren 6.dp yayılma değeri
    • Gölgeyi yarı şeffaf yapan 0.5f alfa değeri
  • Gölge tanımlandıktan sonra .background() değiştirici uygulandı.
    • Box beyaz renkle doldurulur.
    • Arka plan, gölgeyle aynı yuvarlatılmış dikdörtgen şeklinde kırpılır.

Sonuç

Beyaz dikdörtgen şeklin etrafında gri bir gölge.
Şekil 2. Şeklin etrafında çizilen bir gölge.

İç gölgeler uygulama

dropShadow() efektinin tersini oluşturmak için Modifier.innerShadow() efektini kullanın. Bu efekt, bir öğenin altındaki yüzeye gömülü veya basılı olduğu izlenimini verir.

İç gölge oluştururken sıralama önemlidir. innerShadow() değiştiricisi, içeriğin üstüne çizim yapar. Gölgenin görünür olduğundan emin olmak için genellikle aşağıdaki adımları uygularsınız:

  1. Arka plan içeriğinizi çizin.
  2. İçbükey görünüm oluşturmak için innerShadow() değiştiricisini uygulayın.

innerShadow(), arka planın önüne yerleştirilirse arka plan, gölgenin üzerine çizilir ve gölgeyi tamamen gizler.

Aşağıdaki örnekte, RoundedCornerShape üzerinde innerShadow() uygulaması gösterilmektedir:

@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
            )
        }
    }
}

Beyaz dikdörtgen şeklin içinde gri iç gölge.
Şekil 3. Köşeleri yuvarlatılmış bir dikdörtgen üzerinde Modifier.innerShadow() uygulaması.

Kullanıcı etkileşimiyle gölgeleri canlandırma

Gölgelerinizin kullanıcı etkileşimlerine yanıt vermesini sağlamak için gölge özelliklerini Compose'un animasyon API'leriyle entegre edebilirsiniz. Örneğin, kullanıcı bir düğmeye bastığında gölge değişerek anında görsel geri bildirim sağlayabilir.

Aşağıdaki kod, gölgeli bir "basılı" efekti oluşturur (yüzeyin ekrana doğru itildiği yanılsaması):

@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",
                    // ...
                )
            }
        }
    }
}

Kodla ilgili önemli noktalar

  • transition.animateColor ve transition.animateFloat ile basıldığında animasyon uygulanacak parametrelerin başlangıç ve bitiş durumlarını bildirir.
  • updateTransition kullanır ve tüm animasyonların senkronize edildiğini doğrulamak için seçilen targetState (targetState = isPressed) ile birlikte sağlar. isPressed her değiştiğinde geçiş nesnesi, tüm alt özelliklerin animasyonunu mevcut değerlerinden yeni hedef değerlerine otomatik olarak yönetir.
  • Geçişin zamanlamasını ve yumuşatmasını kontrol eden buttonPressAnimation spesifikasyonunu tanımlar. 400 milisaniye süreli bir tween (ara geçiş) ve EaseInOut eğrisi belirtir. Bu, animasyonun yavaş başlayıp ortada hızlanacağı ve sonda yavaşlayacağı anlamına gelir.
  • Aşağıdakiler de dahil olmak üzere görsel öğeyi oluşturmak için tüm animasyonlu özellikleri uygulayan bir değiştirici işlev zinciriyle Box tanımlar:
    • .clickable(): Box öğesini etkileşimli hale getiren bir değiştirici.
    • .dropShadow(): Önce iki dış gölge uygulanır. Renk ve alfa özellikleri, animasyonlu değerlere (blueDropShadow vb.) bağlıdır ve ilk yükseltilmiş görünümü oluşturur.
    • .innerShadow(): Arka planın üzerine iki iç gölge çizilir. Özellikleri diğer animasyonlu değer grubuna (innerShadowColor1 vb.) bağlıdır ve girintili görünümü oluşturur.

Sonuç

Şekil 4. Kullanıcı bastığında animasyonlu bir gölge gösterilir.

Gradyan gölgeler oluşturma

Gölgeler düz renklerle sınırlı değildir. Gölge API'si, degrade gölgeler oluşturmanıza olanak tanıyan bir Brush kabul eder.

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
    )
}

Kodla ilgili önemli noktalar

  • dropShadow(), kutunun arkasına gölge ekler.
  • brush = Brush.sweepGradient(colors), gölgeyi önceden tanımlanmış colors listesinde dönen bir gradyanla renklendirerek gökkuşağı benzeri bir efekt oluşturur.

Sonuç

"Nefes alma" animasyonuyla gradyan dropShadow() oluşturmak için fırçayı gölge olarak kullanabilirsiniz:

Şekil 5. Animasyonlu gradyan gölge.

Gölgeleri birleştirme

Çeşitli efektler oluşturmak için dropShadow() ve innerShadow() değiştiricilerini birleştirip katmanlar halinde uygulayabilirsiniz. Aşağıdaki bölümlerde, bu teknikle nasıl neumorfik, neobrutalist ve gerçekçi gölgeler oluşturacağınız gösterilmektedir.

Neomorfik gölgeler oluşturma

Neomorfik gölgeler, arka plandan organik olarak ortaya çıkan yumuşak bir görünüme sahiptir. Neomorfik gölgeler oluşturmak için aşağıdakileri yapın:

  1. Arka planıyla aynı renkleri paylaşan bir öğe kullanın.
  2. İki hafif, zıt gölge uygulayın: bir köşeye açık renkli bir gölge ve karşı köşeye koyu renkli bir gölge.

Aşağıdaki snippet, nöomorfik efekti oluşturmak için iki dropShadow() değiştiricisini katmanlar:

@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)
    )
}

Beyaz arka plan üzerinde neumorfik efektli beyaz dikdörtgen şekil.
Şekil 6. Neomorfik gölge efekti.

Neobrutalist gölgeler oluşturma

Neo-brütalist tarzda yüksek kontrast, bloklu düzenler, canlı renkler ve kalın kenarlıklar kullanılır. Bu efekti oluşturmak için aşağıdaki snippet'te gösterildiği gibi sıfır bulanıklık ve belirgin bir ofset içeren bir dropShadow() kullanın:

@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
                )
            }
        }
    }
}

Sarı arka plan üzerinde mavi gölgeli beyaz bir dikdörtgeni çevreleyen kırmızı bir kenarlık.
Şekil 7. Neobrutalist gölge efekti.

Gerçekçi gölgeler oluşturma

Gerçekçi gölgeler, fiziksel dünyadaki gölgeleri taklit eder. Birincil ışık kaynağı tarafından aydınlatılmış gibi görünürler. Bu da hem doğrudan gölge hem de daha dağınık bir gölge oluşturur. Aşağıdaki snippet'te gösterildiği gibi, gerçekçi gölge efektleri oluşturmak için farklı özelliklere sahip birden fazla dropShadow() ve innerShadow() örneğini üst üste yerleştirebilirsiniz:

@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
            )
        }
    }
}

Kodla ilgili önemli noktalar

  • Farklı özelliklere sahip iki zincirleme dropShadow() değiştirici ve ardından bir background() değiştirici uygulanır.
  • Bileşenin kenarında metalik jant efekti oluşturmak için zincirleme innerShadow() değiştiriciler uygulanır.

Sonuç

Önceki kod snippet'i aşağıdakileri üretir:

Siyah yuvarlak bir şeklin etrafında beyaz gerçekçi bir gölge.
Şekil 8. Gerçekçi bir gölge efekti.