반응형
[안드로이드] Inner Shadow, Drop Shadow 처리하는 방법
사이드 프로젝트를 진행하면서 figma를 확인하여 UI 작업을 하고 있었다. figma에 그려진 UI 중에 Effect란에 Inner Shadow, Drop Shadow가 포함되어 있는 부분이 존재해서 이를 처리할 방법을 궁리해보거나 자료를 찾아보았다.
Modifier.shadow
- 그림자를 처리하기 위해 Modifier에서 기본적으로 제공하는 함수
@Stable
fun Modifier.shadow(
elevation: Dp,
shape: Shape = RectangleShape,
clip: Boolean = elevation > 0.dp,
ambientColor: Color = DefaultShadowColor,
spotColor: Color = DefaultShadowColor,
) = if (elevation > 0.dp || clip) {
inspectable(
inspectorInfo = debugInspectorInfo {
name = "shadow"
properties["elevation"] = elevation
properties["shape"] = shape
properties["clip"] = clip
properties["ambientColor"] = ambientColor
properties["spotColor"] = spotColor
}
) {
graphicsLayer {
this.shadowElevation = elevation.toPx()
this.shape = shape
this.clip = clip
this.ambientShadowColor = ambientColor
this.spotShadowColor = spotColor
}
}
} else {
this
}
- 해당 함수의 경우 elevation을 이용하여 그림자의 세기를 조절할 수 있다.
- 하지만 그림자의 중심에 offset을 설정할 수 없는 것을 알 수 있다.
Custom Inner Shadow
fun Modifier.innerShadow(
shape: Shape,
color: Color,
blur: Dp,
offsetY: Dp,
offsetX: Dp,
spread: Dp
) = drawWithContent {
drawContent()
val rect = Rect(Offset.Zero, size)
val paint = Paint().apply {
this.color = color
this.isAntiAlias = true
}
val shadowOutline = shape.createOutline(size, layoutDirection, this)
drawIntoCanvas { canvas ->
canvas.saveLayer(rect, paint)
canvas.drawOutline(shadowOutline, paint)
val frameworkPaint = paint.asFrameworkPaint()
frameworkPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
if (blur.toPx() > 0) {
frameworkPaint.maskFilter = BlurMaskFilter(blur.toPx(), BlurMaskFilter.Blur.NORMAL)
}
paint.color = Color.Black
val spreadOffsetX = offsetX.toPx() + if (offsetX.toPx() < 0) -spread.toPx() else spread.toPx()
val spreadOffsetY = offsetY.toPx() + if (offsetY.toPx() < 0) -spread.toPx() else spread.toPx()
canvas.translate(spreadOffsetX, spreadOffsetY)
canvas.drawOutline(shadowOutline, paint)
canvas.restore()
}
}
- shape : 그림자의 모양 지정
- color : 그림자의 색 지정
- blur : 그림자의 세기 지정
- offsetY : Y 축 offset 지정
- offsetX : X 축 offset 지정
- spread : 그림자의 퍼진 정도 지정
적용
- 피그마 이미지
- Compose Device Preview
Custom Drop Shadow
fun Modifier.dropShadow(
shape: Shape,
color: Color = Color.Black.copy(0.25f),
blur: Dp = 4.dp,
offsetY: Dp = 4.dp,
offsetX: Dp = 0.dp,
spread: Dp = 0.dp
) = this.drawBehind {
val shadowSize = Size(size.width + spread.toPx(), size.height + spread.toPx())
val shadowOutline = shape.createOutline(shadowSize, layoutDirection, this)
val paint = Paint().apply {
this.color = color
}
if (blur.toPx() > 0) {
paint.asFrameworkPaint().apply {
maskFilter = BlurMaskFilter(blur.toPx(), BlurMaskFilter.Blur.NORMAL)
}
}
drawIntoCanvas { canvas ->
canvas.save()
canvas.translate(offsetX.toPx(), offsetY.toPx())
canvas.drawOutline(shadowOutline, paint)
canvas.restore()
}
}
- shape : 그림자의 모양 지정
- color : 그림자의 색 지정
- blur : 그림자의 세기 지정
- offsetY : Y 축 offset 지정
- offsetX : X 축 offset 지정
- spread : 그림자의 퍼진 정도 지정
적용
- 피그마
- Compose Device Preview
결론
위에 제시한 코드를 사용하면 피그마의 inner shadow와 drop shadow와 같은 효과를 낼 수 있다. 그리고 해당 방식을 통하면 기존의 Modifier.shadow와 다르게 Multiple Shadow를 적용할 수 있다.
참고자료
https://medium.com/@kappdev/inner-shadow-in-jetpack-compose-d80dcd56f6cf
https://issuetracker.google.com/issues/160665122?pli=1
반응형
'Android > Compose' 카테고리의 다른 글
Orbit 없이 MVI 패턴 적용기 (0) | 2024.09.08 |
---|---|
아이나비 맵 SDK Compose로 사용해보기 (1) | 2024.09.02 |
[안드로이드] Jetpack Compose UI Test 맛보기 (0) | 2024.05.12 |
[안드로이드] Compose 밑줄 텍스트와 클릭 가능하게 만들기 (0) | 2024.05.04 |
[안드로이드] Composable 함수의 속성 (0) | 2024.04.08 |