[Android] 반응형 UI 구현 방법론
아래 영상을 보고 요약한 글입니다. 요약본을 백 번 읽는 것보다 원본 영상을 한 번 보는 게 낫습니다. 이 글은 개인적인 기록용입니다.
반응형 UI란 화면 크기에 따라 서로 다른 UI를 보여주는 것이다. 작은 화면에서와 달리 큰 화면에서는 더 많은 정보를 한 번에 보여줄 수 있다. 일반적인 바 형태의 스마트폰용 UI를 태블릿(특히 가로 모드)에서 그대로 보여주면 어색할 뿐 아니라 사용자의 생산성도 방해할 수 있다. 따라서 화면 크기에 따라 서로 다른 UI를 보여주는 것이 바람직하다.
Compose에서 반응형 UI를 구현하는 대략적인 방법론을 공부해 보자. 자세한 구현 방법은 다른 글에서 작성해 보겠다.
화면 크기
반응형 UI를 구현하려면 먼저 반응할 화면의 크기를 정해야 한다. 화면 너비는 600dp, 840dp를 기준으로 하여 세 단계로 나눌 수 있다.
- 600dp 이하: ``Compact``
- 600dp 초과 840dp 이하: ``Medium``
- 840dp 초과: ``Expanded``
Compact는 전통적인 바 형태의 스마트폰, Medium은 옆으로 접는 폴더블 또는 작은 태블릿, Expanded는 태블릿 등이 해당된다. 이처럼 다양한 크기의 UI를 지원하려면 Compose로 작성하는 게 편하다. XML로 하려면 UI마다 XML을 따로 작성해야 하므로 영 불편하다. Compose로 해 보자.
참고로 화면 높이는 다음과 같이 나눌 수 있다. 너비와 높이 중 무엇으로 나눠야 할 지 고민해 보자. 물론 너비와 높이 둘 다 나눌 수도 있지만, 9종류의 UI를 작성하기는 쉽지 않을 것이다.
Navigation
Navigation 구조는 하나로 하고, 각 Composable에서 화면의 너비에 따라 반응형 UI를 구현하자. 각 composable이 반응형 UI 조각이 되는 것이다.
아래 그림처럼 화면 크기에 따라 서로 다른 navigation 구조를 만드는 방법은 추천되지 않는다. 반응형 UI에서는 화면의 크기가 언제든지 바뀔 수 있음을 전제하는데, 화면 크기에 따라 navigation을 분리하면 너비가 바뀔 때마다 navigation graph를 옮겨가야 한다. 틀림없이 매우 귀찮고 복잡한 작업이다. 으악!
Case study: Now in Android
구글의 공식 샘플 앱인 Now in Android에서 반응형 UI를 어떻게 구현했는지 살펴 보자. 굳이 반응형 UI가 아니더라도 Compose 개발자라면 꼭 읽어보자. 정말 좋은 샘플이다. 물론 나도 다 못 읽었지만..
말했듯이 navigation은 하나만 작성했고
화면 크기에 따라 각 composable을 다르게 보여준다. 아래 코드는 Navigation을 화면 크기에 따라 다르게 보여주는 코드이다. 코드에 쓰인 ``WidthSizeClass``는 ``material3-window-size-class`` 라이브러리에 정의되어 있다.
UI Composable에서 화면 크기에 따라 레이아웃을 다르게 구성하는 예시이다. Width가 expanded인 경우에는 두 줄로, 상대적으로 작은 화면에서는 한 줄로 데이터를 보여준다.
테스트
Navigation을 동일하게 하면 ViewModel unit test를 하나만 작성해도 된다. 데이터의 표현(UI)이 여러 개 존재하더라도 데이터는 동일하기 때문이다. 위에서 navigation을 나누지 말라고 한 이유이기도 하다.
Configuration change 상황에서 데이터가 제대로 보존되는지 확인할 수도 있다.
물론 UI 테스트는 크기별로 따로 작성해야 한다. UI가 여러 개이기 때문에 어쩔 수 없다.
프리뷰
최상위 composable에 화면 크기 정보를 전달하기만 하면 반응형 프리뷰를 볼 수 있다. 참 쉽죠?
반응형 UI with ViewModel
반응형 UI를 작성할 때는 화면 크기가 언제든지 바뀔 수 있다는 점을 고려해야 한다. 일반적으로 configuration change 상황에서 데이터를 보존하는 가장 좋은 방법은 AndroidX ViewModel을 사용하는 것이다.
ViewModel이 UI에 데이터를 제공하는 역할만 충실히 하고 있다면, 반응형 UI를 구현하더라도 ViewModel을 수정할 필요는 없다.
참고문헌
이쁘다..
2편으로 이어집니다.