위 사진에서 사진이 들어간 Box의 Top, Bottom, Left, Right에 Custom Shadow를 부여하고자 한다.
XML의 경우 drawable에서 shadow_corner 와 같은 느낌으로 따로 shape 정하고, 일일히 색을 겹쳐가며 만들어본 기억이 존재한다.
https://github.com/hwisulee/CRCS/blob/main/CRCS/app/src/main/res/drawable/background01.xml
위 주소가 내가 예전에 사용했던 shadow.xml의 대표적인 예시이고 인터넷에서도 쉽게 찾아볼 수 있는 사례이다.
Jetpack Compose에서는 그림자를 어떻게 구현할 수 있을까?
단순히 Modifier.shadow를 사용하면 간단하게 되긴하지만, 커스텀이 안된다는 단점이 존재했다.
좀 더 검색을 거쳐 공식 지원이 뭔가 없기에 사용자들이 대체할만한 코드를 각자 만들어 사용하고 있다는 것을 알게 되었다.
그 중 괜찮아 보이는 녀석을 선별했다.
@Composable
fun ShadowTest() {
val padding = 30.dp // 1
val density = LocalDensity.current
Surface(
shape = RectangleShape, // 2
color = Color.White, // 3
shadowElevation = 16.dp, // 4
modifier = Modifier
.fillMaxWidth() // 5
.height(500.dp) // 6
.padding(padding)
.drawWithContent {
val paddingPx = with(density) { padding.toPx() }
clipRect(
top = -paddingPx, // 7
left = -paddingPx, // 8
right = size.width + paddingPx, // 9
bottom = size.height + paddingPx // 10
) { this@drawWithContent.drawContent() }
}
) {
// 11 내부 컨텐츠
}
}
커스텀하기 좋은 부분에 주석으로 표시해놨다.
1. padding이 작아지면 그림자의 범위는 작아지고 내부 컨텐츠 크기는 커진다.
|
|
padding = 10.dp | padding = 30.dp |
2. 컨텐츠의 모양이 변한다.
shape = RectangleShape | shape = CircleShape |
어떤 종류의 shape이 존재하는지와 커스텀 shape를 만들 수 있는 방법에 대해서는 아래 링크를 참고하면 좋을 것이다.
https://foso.github.io/Jetpack-Compose-Playground/foundation/shape/
https://foso.github.io/Jetpack-Compose-Playground/cookbook/how_to_create_custom_shape/
https://developer.android.com/develop/ui/compose/graphics/draw/shapes?hl=ko
3. Surface의 배경색 변경
Surface의 배경색을 바꿀 수 있다. Modifier.background(Color.white)와 같은 방식이다.
4. 그림자의 고도 변경
shadowElevation = 30.dp | shadowElevation = 16.dp |
고도가 길면 컨텐츠의 padding 여백에 꽉 찰만큼 그림자가 강하게 생겨 경계가 뚜렷해지지만, 고도가 짧으면 여백이 남기 때문에 한층 자연스러워 보일 수 있다.
padding과 shadowElevation 이후 서술될 길이도 그렇지만 이런 수치 모두 자신의 상황에 맞게 자연스럽게 표현될 수 있도록 조절하는게 좋다.
5, 6. Modifier의 width, height
Surface의 너비와 높이를 지정하는 기본적인 Jetpack Compose의 요소이므로 설명할 필요가 없을 것이다.
7 ~ 10. Shadow의 길이 조절
여기서 top과 left는 음수여야한다. (양수일 경우, top은 아래로 left는 오른쪽으로 증가하기 때문에 그림자가 Surface에 가려진다.)
특정 부분의 그림자를 제거하고 싶다면 top = 0f와 같은 형식으로 바꾸면 된다.
그림자의 길이를 늘리고 싶다면
top & left -> -(paddingPx + num)
right -> size.width + num + paddingPx
bottom = size.height + num + paddingPx
같은 느낌으로 작성하면 된다.
top과 left는 그리는 시작점이기에 괜찮으나, right, bottom은 surface의 우측 끝과 하단에서부터 그려져야하기 때문이다.
11. 내부컨텐츠
여기에 Image를 넣든, Text를 넣든, 여러 Layout을 추가하든 하면 된다.
실제로 켜보면 이런 느낌이다.
'개발 > 안드로이드' 카테고리의 다른 글
AnimatedVisibility()와 MutableTransitionState() (0) | 2024.05.07 |
---|---|
Scaffold와 LazyColumn (1) | 2024.05.03 |
Jetpack Compose에서의 State (0) | 2024.04.30 |
Firebase - 구글 로그인 연동 / 이메일 회원가입 (0) | 2024.02.02 |
UI 공부 (0) | 2024.01.16 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!