카테고리 없음

[ Android ] ViewTreeObserver - View 의 크기 구하기

쉽코기 2022. 2. 21. 23:33

1.  문제상황

View 의 크기를 구해서 특정 작업을 진행하려는데 계속 view의 크기가 0 이라는 답을 얻었다. 문제를 확인해보니 View가 그려지기 전에 그 크기에 접근했기 때문이라고 한다. 실제로 View 는 onResume 에서 그려지기 때문에 이를 위해서 ViewTreeObserver 를 사용했다.

 

2.  ViewTreeObserver

이름 그대로 ViewTree에 대한 옵저버 역할을 하며 옵저버의 리스너를 등록하면 ViewTree 의 변화를 감지할 수 있다.
리스너로는 아래와 같은 리스너를 선택하여 변화를 감지 할 수 있다.

https://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener

 

ViewTreeObserver.OnGlobalLayoutListener  |  Android Developers

android.net.wifi.hotspot2.omadm

developer.android.com

 

3. 주의

ViewTreeObserver.XX 의 리스너를 생성하고 등록한뒤에는 반드시 remove 해주는 것 이 필요하다.

제거해주시 않으면 어떤 리스너를 생성하던 끊임 없이 호출되어 메모리를 낭비할 수 있다.

 

그리고 이때 OnDrawListener 를 채택하여 사용하였는데 draw 리스너는 리스너의 삭제를 오버라이딩 한 공간에서 할 수 없는지라 대체로 OnGlobalLayoutListener 를 선택 해서 사용했다.

이에 대한 정확한 이유는 찾지 못했다.....

 

removeOnXX 리스너 함수를 제공하고 있습니다.

 

4. 사용 예제

 

1. 리스너를 생성합니다.

      val viewDrawingListener = object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                Log.d(TAG, binding.smileImageButton.width.toString())
                binding.smileImageButton.layoutParams.height = binding.smileImageButton.width
                binding.smileImageButton.requestLayout()
                binding.smileImageButton.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }

2. 리스너를 옵저버에 등록해줍니다.

binding.smileImageButton.viewTreeObserver.addOnGlobalLayoutListener (viewDrawingListener )

3. 전체 코드

package com.example.kotlin_cardgame

import android.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.ViewGroup
import android.view.ViewTreeObserver
import com.example.kotlin_cardgame.databinding.ActivityMainBinding

private const val TAG = "MainActivity"

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setImageButtonSize()


    }

    private fun setImageButtonSize() {

        val viewDrawingListener = object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                Log.d(TAG, binding.smileImageButton.width.toString())
                binding.smileImageButton.layoutParams.height = binding.smileImageButton.width
                binding.smileImageButton.requestLayout()
                binding.smileImageButton.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        }

        binding.smileImageButton.viewTreeObserver.addOnGlobalLayoutListener (viewDrawingListener )

    }


}