티스토리 뷰

반응형

ViewTreeObserver 단어를 뜯어보면 View Tree + Observer 로 나눌 수 있습니다.

 

Android Developers 에서는 View Tree Observer를 다음과 같이 표현하고 있습니다.

View Tree Observer는 리스너 등록을 통하여 View Tree 안에서의 변화를 감지할 수 있습니다.

A view tree observer is used to register listeners that can be notified of global changes in the view tree. Such global events include, but are not limited to, layout of the whole tree, beginning of the drawing pass, touch mode change.... A ViewTreeObserver should never be instantiated by applications as it is provided by the views hierarchy. Refer to View.getViewTreeObserver() for more information.






사용방법

 

ViewTreeObserver에 대해서 어느정도 감은 잡았을거 같은데요. 그렇다면 어떻게 사용 하는것인지 알려드리겠습니다.
상황을 만들고 설명하는게 더 좋을거 같습니다.

사용자가 검색 화면에 진입했을 때 검색어 입력창(EditTextView)에 포커스를 두고 키보드를 보여주고 싶습니다.
ViewTreeObserver의 존재조차 몰랐을 경우 onCreated(또는 onCreatedView)에 키보드 보여주는 코드를 넣을 것입니다.
일부 기기는 보여지나 다른 기기에서는 동작 안하는 이슈를 발견하게됩니다.

좀 더 생각을 한다면 Handler.PostDelay() 로 뷰가 다 그려졌겠다 싶을 시간에 키보드를 보여주는 로직을 넣을 것입니다.
하지만 이 방법은 타이밍 이슈가 발생할 수 있습니다.

이런 불편함을 해결하는 방법으로 ViewTreeObserver을 통하여 View가 그려졌을 때를 notice 받아서 처리하도록 합니다.
전체 View가 그려졌음을 판단하는 함수는 viewTreeObserver.addOnGlobalLayoutListener 을 사용하면 됩니다.

여기서 주의할 점은 viewTreeObserver의 대상은 가장 상단 View로 지정해야합니다.
코틀린으로 작성된 소스를 보겠습니다.

// 전체 View가 들어있는지 Listener 등록
rootView.viewTreeObserver.addOnGlobalLayoutListener(
  object : ViewTreeObserver.OnGlobalLayoutListener {
    override fun onGlobalLayout() {
        etSearch.post{
                etSearch.requestFocus()
             etSearch.showKeyboard()
      }
      // 1회성을 위해 Listener 제거
       rootView.viewTreeObserver.removeOnGlobalLayoutListener(this)
    }
  })


옵저버 리스너를 등록한 후 변경에 있을 때 1회만 할 경우 반듯이 리스너를 제거해야 합니다. 만약 제거를 안했을 경우 무한 리스너 호출에 걸릴 수 있습니다.

 

반응형

 

다양한 ViewTreeObserve

 

dwfox 님의 블로그에 유용한 리스너를 깔끔히 정리하여 참고하여 작성하였습니다.

용도에 맞춰서 사용한다면 다양한 이벤트처리를 자유롭게 할 수 있을 것으로 예상됩니다.

형태 Listener 용도
interface ViewTreeObserver.OnDrawListener 뷰를 그릴 때
interface ViewTreeObserver.OnGlobalFocusChangeListener 전체 뷰의 포커스가 바뀔 때
interface ViewTreeObserver.OnGlobalLayoutListener 전체 뷰가 그려질 때
interface ViewTreeObserver.OnPreDrawListener 뷰가 그려지기 전
interface ViewTreeObserver.OnScrollChangedListener 스크로 상태의 변경시
interface ViewTreeObserver.OnTouchModeChangeListener 터치 모드 변경시
interface ViewTreeObserver.OnWindowAttachListener 뷰의 계층구조에 붙을 때와 떨어져 나갈때
interface ViewTreeObserver.OnWindowFocusChangeListener 윈도우 포커스 변경시



 

마무리

화면이 그려지기 전에 크기를 측정 시 NULL 또는 0 의 값을 나올 때가 있습니다.

ViewTreeObserver 를 몰랐던 저는 Handler.PostDelay 을 통하여 처리하였는데요.

ViewTreeObserver 을 알고부터는 타이밍 이슈가 발생할 위험성을 막을 수 있었습니다.

UI 구성하는데 보다 자유로워지길 희망하며 글을 마칩니다.



참고사항

 

https://developer.android.com/reference/android/view/ViewTreeObserver.html?hl=ko

https://dwfox.tistory.com/30

반응형
댓글