-
[ 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 ) } }