ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ 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 )
    
        }
    
    
    }

    댓글

Designed by Tistory.