Android/Android

[Compose] Custom BoxShadow를 만들어보자!

RIEN😚 2023. 4. 4. 19:43
728x90
반응형

토이 프로젝트를 진행하던 중....

👇🏻 요런 느낌의 BoxShadow를 원했지만

 

Surface의 elevation으로만으로는 만족스러운 결과물을 만들수 없었습니다. 😭

하지만 UI에는 진심인 개발자로서 Custom BoxShadow를 만드는 방법에 대해서 찾아보았습니다. 🔥🔥

 

결과적으로는 👇🏻아래와 같이 기획이라는 쪼~금 다르지만 만족스러운 Preview를 만들 수 있었습니다. 👍🏻

 

코드를 잠깐 확인해보면

fun Modifier.shadow(
    color: Color, // 그림자 색상
    elevation: Dp = 0.dp, // 그림자 offset
    spread: Float = 30f // 그림자 퍼짐(?) 정도
) = this.drawBehind { /* */ }

Modifier로 쉽게 적용할 수 있도록 Modifier의 확장함수로 만들어 사용하고 있습니다.

 

1. drawBehind

Modifier가 적용되는 content 뒤!에 draw 작업을 하는 Modifier입니다.

주어지는 이미지, 정확히는 이미지를 포함하는 Surface 뒤에 Shadow를 그려줄 예정이므로 drawBehind가 필요합니다. 🤗

 

2. drawIntoCanvas

적당한 Shadow를 화면에 직접 그리기 위해 Canvas를 준비해줍니다.

this.drawIntoCanvas { /* */ }
그림자 그리기! 🪴
this.drawIntoCanvas {
    val paint = Paint()
    val frameworkPaint = paint.asFrameworkPaint()
    frameworkPaint.color = transparentColor
    // 그림자 크기와 위치 설정
    frameworkPaint.setShadowLayer(
        spread,
        elevation.toPx(),
        elevation.toPx(),
        shadowColor
    )
    // 실제 그리는 부분
    it.drawRect(
        0f,
        0f,
        this.size.width,
        this.size.height,
        paint
    )
}

 

3. 전체 코드

더보기
fun Modifier.shadow(
    color: Color, // 그림자 색상
    elevation: Dp = 0.dp, // 그림자 offset
    spread: Float = 30f // 그림자 퍼짐(?) 정도
) = this.drawBehind {
    val transparentColor = android.graphics.Color.toArgb(color.copy(alpha = 0.0f).value.toLong())
    val shadowColor = android.graphics.Color.toArgb(color.copy(alpha = 1f).value.toLong())
    this.drawIntoCanvas {
        val paint = Paint()
        val frameworkPaint = paint.asFrameworkPaint()
        frameworkPaint.color = transparentColor
        // 그림자 크기와 위치 설정
        frameworkPaint.setShadowLayer(
            spread,
            elevation.toPx(),
            elevation.toPx(),
            shadowColor
        )
        // 실제 그리는 부분
        it.drawRect(
            0f,
            0f,
            this.size.width,
            this.size.height,
            paint
        )
    }
}

 

4. 사용해보기

저는 Surface를 커스텀하게 사용하기 위해 별도의 Component로 만들어 사용하고 있습니다. 🤗

이렇게 만들어둔 Component를 Preview에서 호출해보겠습니다. 🔥👍🏻

@Preview(name = "Surface")
@Composable
fun SurfacePreview() {
    AllForMemoryTheme {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Brush.linearGradient(HarooTheme.colors.interactiveBackground))
        ) {
            HarooSurface(
                modifier = Modifier.padding(10.dp).size(120.dp),
                elevation = 10.dp
            ) {
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .background(HarooTheme.colors.uiBackground)
                )
            }
        }
    }
}

만족스러운 Shadow를 가지는 Surface가 되었습니다. 👏🏻👏🏻👏🏻👏🏻

 

반응형