Android

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

728x90

 

 

ViewTreeObserver란?

Android Developers에서는 ViewTreeObserver를 다음과 같이 설명하고 있다.

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.

간단하게 설명하면 이름 그대로 ViewTree에 대한 옵저버 역할이라고 볼 수 있다.

ViewTreeObserver를 이용하여 리스너를 등록하면 View Tree에서 변경을 감지할 수 있다.

예를 들어, View의 높이를 가져와야 하는 일이 생겼다고 하자. 이때 View.height를 사용해서 높이를 가져오려고 하면 0이 나오게 된다.

이는 View가 화면에 아직 그려지기 전에 높이를 가져오려고 해서 발생한다.

따라서 View가 화면에 그려진 뒤 높이를 가져와야 하므로 화면에 그려졌다는 알림을 받을 수 있는 Observer가 필요하다.

 

 

ViewTreeObserveer 사용 방법

ViewTreeObserver는 View.getViewTreeObserver() 메서드를 통해 접근할 수 있다.

/**
 * Returns the ViewTreeObserver for this view's hierarchy. The view tree
 * observer can be used to get notifications when global events, like
 * layout, happen.
 *
 * The returned ViewTreeObserver observer is not guaranteed to remain
 * valid for the lifetime of this View. If the caller of this method keeps
 * a long-lived reference to ViewTreeObserver, it should always check for
 * the return value of {@link ViewTreeObserver#isAlive()}.
 *
 * @return The ViewTreeObserver for this view's hierarchy.
 */
public ViewTreeObserver getViewTreeObserver() {
    if (mAttachInfo != null) {
        return mAttachInfo.mTreeObserver;
    }
    if (mFloatingTreeObserver == null) {
        mFloatingTreeObserver = new ViewTreeObserver(mContext);
    }
    return mFloatingTreeObserver;
}

 

 

간단한 예시 코드를 보자. 아래의 코드는 이미지 뷰가 화면에 그려질 때 이미지 뷰의 높이를 구하는 코드이다.

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

이미지 뷰의 ViewTreeObserver를 가져온 뒤, addOnGlobalLayoutListener()를 통해 리스너를 추가해준다.

여기서 주의할 점은, 옵저버 리스너를 등록한 후 변경 감지를 1회만 할 경우에는 반드시 추가해준 리스너를 제거해야 한다. 만약 제거를 하지 않은 경우엔 무한 리스너 호출이 생길 수 있다. 리스너 제거는 removeOnGlobalLayoutListener()를 통해 할 수 있다.


 

ViewTreeObserver Listener 종류

위의 예시에서는 OnGlobalLayoutListener를 사용했지만, 이 외에도 여러 가지 리스너가 존재한다. 용도에 따라 다른 리스너를 추가해서 응용할 수 있다.

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

 

 

출처

dwfox.tistory.com/30

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

728x90