위의 화면은 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% 낼 수 없었다. 그러다가 문제를 다시 파악하고 검색을 해서 내가 원하는 결과를 얻을 수 있었다.
위의 첨부한 링크는 빠른 시일 내에 읽어보도록 노력할 것이다.