-
안드로이드 그림자(Shadow) 효과 넣기개발/안드로이드 2020. 4. 18. 11:43
안드로이드에서 그림자 효과를 넣는 방법으로는 UI의 elevation 속성 값을 조정하는 것과 직접 그림자용 리소스 파일을 만드는 방법이 있다. 이번 포스트에서는 이 두가지의 사용 방법과 각각의 장단점을 소개해보려고 한다.
1. elevation 값 조정하기
UI에 가장 쉽게 섀도우 효과를 입힐 수 있는 방법이다. 안드로이드 API21 부터 UI 뷰들에 elevation 이라는 속성값이 추가 됐는데 이 값을 넣으면 UI가 Z축으로 위로 튀어나와 그림자 효과를 줄 수 있게 된다.
코드는 다음과 같다.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"> <ImageView android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="50dp" android:elevation="20dp" android:background="@color/colorPrimary" /> </FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout>
elevation 값을 조정해서 효과를 줄 때는 주의해야할 점이 두가지 있는데 첫번째는 elevation 값에 넣어준 수치 만큼 View 주변에 여백을 충분하게 주어야 한다는 것이다. elevation으로 만든 그림자는 View의 width/height 영역 밖에서 발생하기 때문에 이 부분의 여백을 주지 않으면 그림자 효과가 발생하지 않는다.
두번째로는 background값이 투명하면 안된다. 불투명한 값으로 셋팅을 해줘야한다. 왜 불투명한 background 값을 셋팅해줘야하는지는 아직 잘 모르겠다; 하지만 투명한 값으로 세팅하면 그림자 효과가 나타나지 않는다.
이 방법은 편하긴 하지만 API21 버전부터 사용할 수 있고 하단부에만 그림자 효과를 줄 수 있다는 단점이 있다. 상하좌우 모두 그림자 효과를 주어야 할 때는 사용 할 수 가 없다. 이런 경우에는 직접 리소스 파일로 그림자 효과를 만들어야 한다.
2. 그림자용 리소스 파일 만들기
선이나 사각형을 코드로 만들 때 사용했던 XML 파일을 이용해서 그림자 효과를 줄 수 있다. 설명에 앞서서 아래 예시 코드와 이 코드를 입힌 UI 결과물을 먼저 보자. 코드가 길지만 반복 구문이 많으니 대강 훓어보는 것을 추천한다
shadow_test.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <!-- Drop Shadow Stack --> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#00CCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#06CCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#09CCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#0BCCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#0DCCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#10CCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#12CCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#15CCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#17CCCCCC" /> </shape> </item> <item> <shape> <padding android:bottom="2.5dp" android:left="2.5dp" android:right="2.5dp" android:top="2.5dp" /> <solid android:color="#1ACCCCCC" /> </shape> </item> <!-- Background --> <item> <shape> <solid android:color="@android:color/white" /> </shape> </item> </layer-list>
ImageView에 위에서 만든 리소스를 background로 넣었다.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.appcompat.widget.LinearLayoutCompat android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="RtlSymmetry"> <ImageView android:layout_width="150dp" android:layout_height="150dp" android:layout_gravity="center" android:background="@drawable/shadow_test"/> </androidx.appcompat.widget.LinearLayoutCompat> </androidx.constraintlayout.widget.ConstraintLayout>
이 코드를 이용해 그림자 효과를 입혀본 결과는 다음과 같다.
사진을 자세히 보면 흰 사각형 바깥쪽에 촘촘히 작은 선들이 있는 것을 볼 수가 있다. 이건 위 예제 코드에서 2.5dp 기준으로 각각 색깔이 다른 사각형을 넣었기 때문이다. 여러개의 작은 장면들을 조합해서 연속된 애니메이션 효과로 보이게 한 것 처럼 이 그라데이션 효과도 작은 사각형들을 합해서 그림자처럼 보이게 만든 효과다.
이 방법은 약간의 노가다가 필요하긴 하지만 개발자가 그림자 효과를 자유자재로 커스텀이 가능하다는 장점이 있다. 어떤 부분에 좀더 강조를 세게 주고 싶다거나 좌측 상단, 우측 하단, 상화좌우 전체에 그림자 효과를 선택해서 줄 수 있다.
elevation을 이용한 방법과 차이가 있다면 이 방법은 그림자 영역이 뷰의 영역에 포함되어 있다는 것이다. 아래 그림을 보면 왼쪽 그림의 보라색 사각형이 elevation을 이용해서 그림자 효과를 준 경우고 하얀색 사각형이 리소스를 이용해서 그림자 효과를 준 경우인데, 미리보기 상으로는 하얀색 사각형이 더 작아보이지만 두 ImageView의 가로 세로 너비 값은 오른쪽 그림에서도 알 수 있듯이 동일하다. 리소스를 사용하면 그림자 영역을 View 내부에서 사용하기 때문에 원래 생각했던 ImageView의 크기와 약간 차이가 발생 할 수 있다. 상황에 따라서 단점이 될 수도 있고 장점이 될 수 도 있는 기능이라 섣불리 판단 할 수는 없을 것 같다. 단 차이점은 유의해서 알고가는 것이 좋을 것 같다.
'개발 > 안드로이드' 카테고리의 다른 글
MediaCodec - Getting Started (1) 2020.05.24 Navigator - Getting Started (0) 2020.04.20 Kotlin - Coroutine (0) 2020.04.15 Kotlin으로 깔끔한 Builder를 만들어보자 (1) 2020.04.14 Exoplayer2 사용하기 (0) 2020.04.12