[Android] 해상도 대응하기 - XML편(1)

0

Android 해상도 대응

목록 보기
1/1
post-thumbnail

전문적인 모바일 플랫폼 회사에 오게되면서 해상도 대응은 가장 중요한 일중 하나라는것을 배웠습니다.(전 회사들은 UI에 그렇게 신경쓰지 않았던...)
해상도에 따라 View가 변경되면 어떻게 코드로 대응할지 차근차근 알아봅시다.

문제 시작!

예를 들어 위와 같은 레이아웃을 디자이너에게 요청 받았습니다.
자세하게 설명해보면, 480dp에서는 버튼이 세로로 보여야 하며 가로에서는 양옆으로 붙어야 합니다.

만약 버튼값이 고정되어 있거나 최소값이 정해져 있다면 코드없이
FlexBoxLayout이나, ConstraintLayout Flow를 이용하여 처리가 가능했을겁니다.

Xml 내부에서 처리할 수 있다면 XML단에서 끝내는게 최선입니다.
Activity로 이동하면 코드가 많이 난잡해지기 때문입니다.

하지만 480dp의 해상도라는 기준이 있고, 버튼이 match_parent 기준일때 코드로 대응을 하는 수 밖에 없습니다.(좋은 의견있다면 아래에 해주세요 ㅎㅎ)

해상도 대응 방법은 아래의 방법들이 있습니다.

  1. View의 ViewTreeObserver 사용하기
  2. OnCreate, OnViewCreated에서 그냥 처리하기
  3. OnConfiguration Changed에서 처리하기

1.View의 ViewTreeObserver 사용하기

예를들어 A의 Width가 360일때 화면을 변경한다라는 조건이 붙었다면, A의 측정이 다끝나고 View를 변경해야합니다.
하지만 OnCreate나 OnViewCreated에서는 뷰의 측정이 끝났다는것을 보장하지 못하기에 0이 나올수 있습니다. 이른바 타이밍 이슈라고들 얘기를 합니다.

그렇기에 View의 측정이 끝났다는 CallBack을 받아야 하는데요.

View.ViewTreeObserver를 사용해 뷰가 그려지고 난 이후, Callback을 받을 수 있습니다.

testView.viewTreeObserver.addOnGlobalLayoutListener(object: ViewTreeObserver.OnGlobalLayoutListener {
    override fun onGlobalLayout() {
        println(testView.height)
        
        //해제
        image_view.viewTreeObserver.removeOnGlobalLayoutListener(this)
    }
})

가장 편하게 구현이 가능하나, 문제는 Callback 내부에서 requestLayout()이 호출된다면, 무한 콜백지옥이 시작될 수 있습니다.

그렇기에 특정 View의 크기를 통해 구현한다면 ViewTreeObserver를 사용하는게 좋아 보입니다.

사족을 붙이자면 ViewTree에서는 아래와 같이 여러가지 Linstener가 존재합니다.

2. OnCreate, OnViewCreated에서 그냥 처리하기

만약 특정 뷰의 사이즈를 알 필요가 없다면, 그냥 OnCreateOnViewCreated에서 호출하는게 좋습니다.

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 	super.onViewCreated(view, savedInstanceState)
          //상태 변경 버튼이 480 이하 사이즈에서는 세로로 배치된다.
        val screenWidthDp = clStateChange.width / resources.displayMetrics.density
        Log.d(TAG, "changeStateConstLayoutOrientation:  $screenWidthDp")

        if (screenWidthDp <= STATE_CHANGE_SIZE) {
            flowPauseUnsubscribe.setOrientation(Flow.VERTICAL)
        } else {
            flowPauseUnsubscribe.setOrientation(Flow.HORIZONTAL)
        }  
 }       

측정이 되지 않은 상태에서 requestLayout()이 호출 된다면 이전 호출은 Skip해 버립니다.
그래서 측정이 되지않은 상태라는 측면에서 본다면 미리 사이즈를 아는것이 불가능하기때문에 1번의 방법을 쓰는게 중요합니다.

3. OnConfigurationChanged() 이용하기

모바일 플랫폼 특성상, 가로 변경이나 접고 열기 같은 동적인 해상도 변화에 대응 해줘야합니다.
Android Manifest에 configChanges를 적용하지 않을경우 , Recreate()를 일으킵니다.

android:configChanges을 안넣으면 ReCreate가 호출된다?


https://developer.android.com/guide/topics/resources/runtime-changes

Recreate()가 일어나면 다시 OnCreate,OnViewCreated가 재호출되기 때문에 (1),(2)을 적용하면 알아서 변경될 겁니다.
하지만 성능 최적화를 위해Recreate()가 일어나지 않게 막았을 경우에는 OnConfigurationChanged()에서 한번 더 처리를 하는게 좋습니다.

참고

[Android] ViewTreeObserver란? - View가 그려지는 시점 알아내기
Handle configuration changes

profile
쉽게 가르칠수 있도록 노력하자

0개의 댓글