위의 화면은 Google의 Material Design을 설명하는 글이나 예제에서 많이 보는 화면이다. 스크롤을 하게 되면 달과 산이 있는 이미지가 사라지면서 Toolbar 형태가 되면서 Title이 위치하게 되는 구조이다.

이것에 대해 설명하는 것은 아니다. 이는 CoordinatoryLayout과 AppbarLayout, CollapsingToolbarLayout, Toolbar를 사용해서 구성할 수 있고, 구글에 많은 예제가 있으니 참고하면 된다.

이번 글에서 설명하려고 하는 것은 내가 겪은 issue와 삽질 과정을 설명하려고 한다.

CoordinatorLayout Status bar issue

이슈의 이름은 내가 그냥 지은 것이다. 왜 이런 이름을 짓게 되었냐면 스크롤을 아래로 해서 내리면 Status bar의 일부가 딸려오는 issue가 발생했기 때문이다. 말로 설명하기에는 쉽지 않아 사진을 첨부했다.

해당 프로젝트는 내가 현재 진행하고 있는 프로젝트의 일부 화면이다. 이 화면은 상세 페이지이고 CoordinatorLayout, AppbarLayout, CollapsingToolbarLayout, Toolbar 를 사용하여 구성했다. 사실 이 4개가 제일 중요하다.

위의 사진은 스크롤을 내리는 상황이다. 자세히 보면 Status bar의 초록색이 밑으로 딸려 가는 모습을 볼 수 있다. 그래서 나는 ‘이게 버퍼링이 걸린 것인가, 혹은 다른 에러가 있는 것인가’ 생각을 해봤다.

그리고 Wanted의 앱을 참고해봤다. 왜냐하면 구글의 Material Design이 가장 잘 반영된 앱이라고 생각을 했기 때문이다. 물론 CoordinatorLayout을 사용한 것으로 추정되는 화면도 있다. 이 화면을 보니 내가 겪은 이슈가 없었다.

먼저, 내 xml 코드를 보자.

xml 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".view.mission.MissionDetailActivity">

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/missionDetailAppbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
android:fitsSystemWindows="true">

<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/missionDetailCollapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="@color/fe_fu_white"
>

<ImageView
android:id="@+id/missionDetailImage"
android:layout_width="match_parent"
android:layout_height="400dp"
android:scaleType="fitXY"
android:src="@drawable/fufe_illust_jh_04"
app:layout_collapseMode="parallax"/>

<androidx.appcompat.widget.Toolbar
android:id="@+id/missionDetailToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/AppTheme.PopupOverlay"
android:background="@android:color/transparent"
app:layout_collapseMode="pin"/>


</com.google.android.material.appbar.CollapsingToolbarLayout>

</com.google.android.material.appbar.AppBarLayout>

<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<LinearLayout
android:layout_marginTop="@dimen/margin_32dp"
android:layout_marginStart="@dimen/margin_32dp"
android:layout_marginEnd="@dimen/margin_32dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="200dp"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<TextView
android:id="@+id/missionDetailTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/fe_fu_black"
android:text="@string/text_mission_detail_title_mock"
style="@style/TitleBlackStyle"
/>

<TextView
android:layout_marginTop="6dp"
style="@style/ContentsBodyStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_mission_detail_content_mock"
/>

<View
android:layout_marginTop="@dimen/margin_16dp"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#e3e3e3"/>

<TextView
android:layout_marginTop="@dimen/margin_32dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DetailContentsBodyStyle"
android:text="옆 동네 토마토를 먹으면,"
/>

<TextView
android:layout_marginTop="@dimen/margin_8dp"
style="@style/ContentsBodyStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="전국 방방곡곡 및 전세계에서 농산물을 실어 나르려면 연료가 많이 들어요. 이렇게 연료를 지나치게 많이 사용하는 것은 대기 오염의 원인이 된답니다."
/>

<TextView
android:layout_marginTop="@dimen/margin_32dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DetailContentsBodyStyle"
android:text="미션 방식"
/>

<TextView
android:layout_marginTop="@dimen/margin_8dp"
style="@style/ContentsBodyStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_mission_detail_mock_data"
/>

<TextView
android:layout_marginTop="@dimen/margin_32dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="미션 효과"
style="@style/DetailContentsBodyStyle"
/>

<TextView
android:layout_marginTop="@dimen/margin_8dp"
style="@style/ContentsBodyStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_mission_detail_mock_data"
/>
</LinearLayout>

</androidx.core.widget.NestedScrollView>

<RelativeLayout
android:id="@+id/missionDetailSelectButtonLayout"
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/border_button_background_active"
android:visibility="visible">

<TextView
style="@style/ButtonWhiteCenterStyle"
android:layout_centerInParent="true"
android:text="@string/text_mission_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</RelativeLayout>

<LinearLayout
android:id="@+id/missionDetailDecideButtonLayout"
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="60dp"
android:visibility="gone"
android:orientation="horizontal">

<TextView
android:id="@+id/missionDetailGiveUpButton"
style="@style/ButtonWhiteCenterStyle"
android:layout_weight="1"
android:gravity="center"
android:text="@string/text_mission_detail_cancel"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/fe_fu_gray"/>

<TextView
android:id="@+id/missionDetailCompleteButton"
style="@style/ButtonWhiteCenterStyle"
android:layout_weight="2"
android:gravity="center"
android:text="@string/text_mission_detail_complete"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/fe_fu_main"/>

</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

여기서 주목해야 할 것은 android:fitsSystemWindows 속성이다. 이는 위의 4개 중에서 Toolbar만 제외하고 모두 true로 설정이 되어있다. 처음에는 큰 신경을 쓰지 않고 구글링을 통해 찾은 자료를 기반으로 구성했는데, 이게 문제가 된 것이었다.

StackOverflow의 답변 중 android:fitsSystemWindows를 false로 설정하라는 부분을 보았다. 그래서 CoordinatorLayout 부분에서 제거를 하니 해당 이슈가 말끔하게 사라진 것이었다.

그래서 android:fitsSystemWindows이 어떤 속성일까 궁금해지기 시작했다. 그래서 다음과 같은 글을 찾게 되었다.

Why would I want to fitsSystemWindows? 아직 읽어보지는 않았지만, 어떻게 이 속성으로 인해 해결을 했는지를 알 수 있을 것 같다.

느낀 점

역시 구글링도 실력인가 보다. 처음에는 감을 못잡아서 이상한 키워드로 검색을 했었다. 그러다가 MotionLayout을 사용해서 만들어봤는데, 내가 원하는 Performance를 100% 낼 수 없었다. 그러다가 문제를 다시 파악하고 검색을 해서 내가 원하는 결과를 얻을 수 있었다.

위의 첨부한 링크는 빠른 시일 내에 읽어보도록 노력할 것이다.