만족

[Android] elevation을 설정했음에도 그림자(shadow)가 표시되지 않는 문제 본문

[Android] elevation을 설정했음에도 그림자(shadow)가 표시되지 않는 문제

FrontEnd/Android Satisfaction 2022. 4. 10. 23:08

css에서 box-shadow를 이용해 그림자 효과를 내듯이,

android 에서는 elevation을 이용해 그림자 효과를 낸다.

 

다만, 위의 이미지처럼 컴포넌트를 위로 띄워 발생하는 그림자라는 컨셉트를 가지고 있어서,

'얼마만큼 컴포넌트를 위로(z축) 띄울 것인가?' 를 지정하는 방식이다.

 

<TextView
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:textAlign="center"
  android:text="elevation 8dp"
  android:elevation="8dp"
  android:padding="64dp"/>

이렇게 elevation이라는 속성을 추가함으로써 손쉽게 그림자를 표시할 수 있지만, 

그림자가 정상적으로 표시되지 않는 문제가 빈번히 발생한다.

 

몇 가지 케이스들을 통해 원인과 해결법을 살펴본다.

 

거두절미하고 결론만 보려면 맨 아래로 스크롤하면 된다.

 

그림자가 생길 공간이 없는 경우

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:background="#ffffff"
        android:text="textView"
        android:padding="64dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:background="#ffffff"
        android:text="elevated textView"
        android:padding="64dp"
        android:elevation="4dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:background="#ffffff"
        android:text="textView"
        android:padding="64dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

 

이 코드에서 두 번째 TextView는 elevation 속성을 가지고 있다.

 

이 경우 그림자가 표시될까?

 

표시되지 않는다.

 

왜냐하면 그림자가 표시될 상하좌우 공간이 확보되지 않았기 때문이다.

 

상하의 경우 1,3번째 컴포넌트가 차지하고 있고,

좌우의 경우 여백이 없기 때문에 그림자가 표시되지 않는다.

 

이 경우 margin을 주어 그림자가 표시될 공간을 확보해 주면 된다.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:background="#ffffff"
        android:text="textView"
        android:padding="64dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:layout_margin="8dp"
        android:background="#ffffff"
        android:text="elevated textView"
        android:padding="64dp"
        android:elevation="4dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:background="#ffffff"
        android:text="textView"
        android:padding="64dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

 

잘 표시된다

 

배경색(background)이 없는 경우

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:text="textView"
        android:padding="64dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:layout_margin="8dp"
        android:text="elevated textView"
        android:padding="64dp"
        android:elevation="4dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:text="textView"
        android:padding="64dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

elevation을 적용한 컴포넌트에 background가 없을 경우에도 그림자가 표시되지 않는다.

 

이 경우 배경색을 설정해 주면 된다.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:text="textView"
        android:padding="64dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:background="#ffffff"
        android:layout_margin="8dp"
        android:text="elevated textView"
        android:padding="64dp"
        android:elevation="4dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:text="textView"
        android:padding="64dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

 

부모(parent) 컴포넌트의 padding에 의해 그림자가 잘리는 경우

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <FrameLayout
        android:padding="16dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:background="#ffffff"
            android:text="elevated textView"
            android:padding="64dp"
            android:elevation="4dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </FrameLayout>
</LinearLayout>

 

FrameLayout이 TextView(elevated)의 부모 컴포넌트이다.

 

FrameLayout에 padding이 걸려 있어 TextView의 그림자가 표시될 것으로 예상할 수도  있겠지만, 공간이 없는 것으로 취급되어 표시되지 않는다.

 

그렇다면 모든 elevated component는 전부 각각 margin을 주는 번거로운 방법으로 그림자를 표시해야 할까?

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <FrameLayout
        android:clipToPadding="false"
        android:padding="16dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:background="#ffffff"
            android:text="elevated textView"
            android:padding="64dp"
            android:elevation="4dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </FrameLayout>
</LinearLayout>

 

부모 컴포넌트에 clipToPadding="false"를 추가하면

padding 공간을 그림자를 표시하는 데 사용할 수 있다.

 

(이 때 아무 컴포넌트에나 clipToPadding 속성을 주는 것이 아니라, 패딩 공간을 가지고 있는 컴포넌트에 주어야 한다.)

 

 

그림자가 잘 표시된다.

 

정리

elevation이 정상적으로 표시되지 않을 때는 아래 사항을 점검한다.

 

1. 그림자가 표시될 공간이 확보되어 있는가?

2. 그림자를 표시할 컴포넌트의 배경색이 지정되어 있는가?

3. 부모 컴포넌트가 padding을 가지고 있으며 이 외의 별도 공간을 확보하지 않았다면, clipToPadding을 지정했는가?

 

아 오랜만에 안드로이드하니까 정신나갈거같다...



Comments