[ReactNative] Dimension과 좌표값

Einere·2022년 8월 3일
3
post-thumbnail

원글 링크: https://kjwsx23.tistory.com/718

회사에서 타입캐스트 스토리 앱을 개발하던 도중, 카드 리스트에서 더보기 버튼을 눌렀을 때 드롭다운 창이 열려서 프로젝트의 이름을 변경하거나 삭제할 수 있는 UI를 구현해야 했다.

Google Pixel 4a와 Samsung Galaxy Note 8 의 화면 차이

원래 픽셀 폰으로 개발을 했었기 때문에 잘 되는줄 알았는데, 노트 폰에서는 드롭다운 창이 bottom tab menu에 가려지는 현상이 발생했다. 그래서 이리저리 원인을 찾던 도중, 엄청난 것을 발견했다.

모바일 디멘션 개념들

본격적인 삽질 후기를 보기 전에, 개념을 먼저 정립하자. (안드로이드 한정)

  • 디바이스의 화면 전체 : screen
  • 상태 창 영역 : status bar
  • 소프트 버튼 영역 : navigation bar
  • window 영역 : screen 영역 - status bar 영역 - navigation bar 영역

기기 간 통일되지 않은 dimension 동작

우선, 스낵으로 만든 테스트용 앱을 픽셀과 노트로 돌려보았다.

Google Pixel 4a와 Samsung Galaxy Note 8의 화면

dimension 과 관련해서 주목할만한 점은,

  • width 는 screen이나 window나 동일하다.
  • height 는 screen이 window보다 더 크다.
  • status bar height 는 기기마다 제각각이다.
  • RN 에서 제공하는 API 로는 navigation bar 의 높이를 알 수 없다.

그리고 여러가지 네모들과 선들이 있는데, 각각의 의미는 다음과 같다. (볼드 체는 기기 별로 다르게 보여지는 요소들)

  • lightgrey 색 박스 : bottom tab menu 영역
  • lightcoral 색 선 : status bar 높이
  • bisque 색 선 : window 높이
  • cadetblue 색 선 : status bar 높이 + window 높이
  • firebrick 색 박스 : status bar 높이 + window 높이 - bottomTabMenuHeight
  • lightblue 색 박스 : bottom 0
  • lightpink 색 박스 : window 높이
  • lightgreen 색 박스 : window 높이 - bottomTabMenuHeight

우선 bottom 속성을 이용해 스타일링한 요소들은 둘 다 의도한대로 bottom navigation bar 바로 위에 착 달라붙어 있는 것을 확인할 수 있다.

top 속성 말고, bottom 속성을 쓰면 되지 않나요? 라고 생각할 수 있다. 하지만
(1) 겹침 여부를 계산하기 위한 레이아웃 값들(pageX, pageY, width, height, ...)이 모두 좌상단이 기준이며,
(2) bottom 속성은 단순히 어디에 요소를 그릴지 정할 뿐이며, 드롭다운 창의 bottom 좌표값과 bottomTabMenu 의 top의 좌표값을 계산하는 과정에서 의도치 않은 동작을 해결해주진 않는다.

기기별로 다르게 보여지는 요소들을 자세히 서술하면 다음과 같다.

  • bisque 색 선
    • pixel : bottom tab menu 위에 렌더링 된다.
    • note : navigation bar 바로 위에 렌더링 된다.
  • cadetblue 색 선
    • pixel : navigation bar 바로 위에 렌더링 된다.
    • note : navigation bar 아래에 렌더링 되어 보이지 않는다.
  • firebric 색 박스
    • pixel : bisque 색 선보다 아래이며, bottom tab menu 와 맞게 렌더링 된다.
    • note : bisque 색 선과 겹치며, 위쪽 일부분은 bottom tab menu 영역에, 아래쪽 일부분은 navigation bar 영역에 렌더링 된다.
  • lightpink, lightgreen 색 박스
    • 두 기기 모두 bisque 색 선 위아래에 붙어서 렌더링 된다.

이러한 사실들로 다음과 같은 결과를 유추할 수 있다.

  1. 노트는 window.heightstatusbar.height 가 포함되어 있다.
  2. 픽셀은 window.heightstatusbar.height 가 포함되어 있지 않다.

따라서, bottom tab bar 의 top 속성 값은 다음과 같다.

  • 노트 : window.height - bottomTabMenuHeight
  • 픽셀 : statusbar.height + window.height - bottomTabMenuHeight

navigation bar 높이와 분기 처리

우연히 미지의 값인 navigationBar.height 값을 계산하던 중, 픽셀과 노트 둘 다 48로 동일한 값이 나온 것을 알게 되었다. 그래서 다음과 같은 가정 하에서는, 해당 기기가 window.heightstatsusbar.height 를 포함하는지 안하는지 판별할 수 있다.

부분의 안드로이드 기기의 navigationBar.height 는 48이다.

따라서 다음과 같이 분기 처리를 할 수 있다.

  1. statusbar.height + window.height + navigationbar.height === screen.height 라면, window.heightstatsusbar.height 가 포함되어 있지 않다.
  2. statusbar.height + window.height + navigationbar.height > screen.height 라면, window.heightstatsusbar.height 가 포함되어 있다.

measure 측정 값들

  1. 모바일 기기의 개발자 모드에서, 포인터 위치 기능을 켠다.
  2. 픽셀 기준 5번째 ProjectCard2 의 dropdown 의 top 위치값이 1917px 로 측정되었다.
  3. 픽셀 폰의 배율은 2.75이므로, 1975px = 697dp
  4. 그런데 pageY 의 값은 648dp
  5. 697 - x = 648, x = 49, 49 = statsusbar.height
  6. screen 기준 측정값과 pageY 값 차이가 statsusbar.height 만큼 나므로, 측정 값들은 window 기준!
  7. 노트 기준 5번째 ProjectCard2 의 dropdown 의 top 위치값이 1765px 로 측정되었다.
  8. 노트 폰의 배율은 2.625이므로, 1765px = 672dp
  9. 그런데 pageY 의 값은 648dp
  10. 672 - x = 648, x = 24, 24 = statsusbar.height
  11. screen 기준 측정값과 pageY 값 차이가 statsusbar.height 만큼 나므로, 측정 값들은 window 기준!

그리고 위 실험을 통해 다음 사실도 알아냈다.

현재 앱의 masure 의 측정 값들은 기기 불문 viewport 의 좌상단을 기준으로 한다. (무엇이 기준인지 확인 필요, 기본적으론 screen이 기준이며, 현재 타캐 앱은 window)

결론

너무 많은 내용때문에 머리가 복잡할까봐, 결론을 정리하자면 다음과 같다.

  1. 안드로이드 기준 디바이스의 화면은 screen, status bar, window, navigation bar 영역으로 구성되어 있다.
  2. (RN Dimension API를 통해 받아오는) window.height 값에 statusbar.height 를 포함하는 기기가 있다.
  3. 대부분의 안드로이드 기기의 navigation bar 영역의 높이는 48dp 이다.
  4. measure 측정 값은 viewport를 기준으로 하며, 기본적으로 viewport는 screen이다.
  5. screen 기준 위치 값과 window 기준 위치 값을 연산할 때는 조심하자.
  6. 혹시라도 관련 값들을 사용해야 한다면, react-native-safe-area-context 라이브러리를 사용하자.

후기

왜 삼성 기기는 window.heightstatusbar.height 를 포함하는 걸까..? 아마 RN 팀이 일을 안하거나, 삼성이 이상하게 만들었거나.. (구글 픽셀 폰은 안드 레퍼런스 폰이니까..)

참고

https://reactnative.dev/docs/dimensions
https://stackoverflow.com/questions/46126521/android-navigation-bar-height-react-native

profile
지속가능한 웹 개발자를 지향합니다. 경험의 공유를 통해 타인에게 도움이 되는 것을 좋아합니다. 사용자에게 가치를 제공하는 것에 기쁨을 느낍니다.

2개의 댓글

comment-user-thumbnail
2022년 12월 22일

글 너무 잘 읽었습니다. 궁금한게 있어서 댓글 남깁니다! 48, 15, 0 총 3가지의 대표적인 네비게이션 바 높이가 있는데 해당 부분에 대해서는 조건으로 테스트 해보셨나요? 제가 테스트 할 때에는 간헐적으로 비정상적으로 표시가 되는 부분이 있었습니다.

1개의 답글