본문 바로가기
안드로이드 자바

[JAVA][Android] ViewTreeObserver 사용 하여 레이아웃 크기 측정과 상태 전환 다루기

by teamnova 2024. 11. 4.
728x90

ViewTreeObserver는 Android 개발에서 뷰의 레이아웃, 크기, 위치 등을 감지하고 이를 활용하기 위해 사용됩니다.

다음은 ViewTreeObserver를 사용할 때 좋은 상황과 그 활용 예시입니다.

 

1. 뷰의 크기나 위치 측정 필요 시

  • 상황: 뷰가 화면에 렌더링된 후에야 크기나 위치를 정확하게 알 수 있는 경우.
  • 예시: 뷰가 화면에 표시된 후 텍스트 크기에 따라 레이아웃을 조정할 필요가 있을 때 사용합니다. 예를 들어, 동적인 텍스트 내용을 가진 텍스트뷰의 높이를 측정하여 다른 뷰의 위치를 조정할 수 있습니다.

2. 레이아웃 변화에 대한 반응 필요 시

  • 상황: 사용자 인터랙션이나 데이터 변경에 따라 레이아웃이 동적으로 변화하는 경우.
  • 예시: 리스트뷰에서 항목이 추가되거나 제거될 때, 전체 레이아웃이 업데이트된 후 특정 뷰의 위치를 다시 계산해야 할 때 유용합니다.

3. 애니메이션이나 전환 효과 적용 시

  • 상황: 뷰의 크기나 위치가 변하는 동안 애니메이션 효과를 적용하고 싶을 때.
  • 예시: UI 요소의 크기를 변화시키며 애니메이션 효과를 주고 싶을 때, 뷰가 레이아웃 패스를 마친 후 크기를 측정하여 애니메이션을 적용할 수 있습니다.

4. 비율 기반 레이아웃 조정 필요 시

  • 상황: 다양한 화면 크기와 비율에 맞게 레이아웃을 조정해야 할 때.
  • 예시: 화면의 비율에 따라 뷰의 크기를 비례적으로 조정해야 할 경우, ViewTreeObserver를 통해 현재 뷰의 크기를 측정하고 비율에 맞춰 다른 뷰의 크기를 조정할 수 있습니다.

5. UI 요소가 완전히 그려진 후 작업 필요 시

  • 상황: UI 요소가 완전히 렌더링된 후에 어떤 작업을 수행해야 할 때.
  • 예시: 이미지 로딩 라이브러리를 사용할 때, 이미지를 성공적으로 로딩한 후 뷰의 크기를 기반으로 다른 UI 요소를 배치하고 싶을 때 사용합니다.

 

MainActivity

import android.os.Bundle;
import android.view.ViewTreeObserver;
import android.view.ViewGroup;
import android.graphics.Color;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    int initialWidth;
    int initialHeight;
    boolean isChanged = false; // 상태 변경 여부 추적

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView textView = findViewById(R.id.myTextView);
        Button changeSizeButton = findViewById(R.id.changeSizeButton);

        // 초기 텍스트 설정
        textView.setText("버튼을 클릭하면 뷰 화면의 크기와 색상이 바뀌어요!");

        // 뷰의 초기 크기 저장 및 ViewTreeObserver 사용
        ViewTreeObserver viewTreeObserver = textView.getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 뷰가 처음 그려졌을 때 크기 저장
                initialWidth = textView.getWidth();
                initialHeight = textView.getHeight();

                // 초기 크기 출력 (콘솔에 로그 찍기)
                System.out.println("초기 크기: " + initialWidth + " x " + initialHeight);

                // 리스너 제거 (초기 크기만 필요하므로)
                textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });

        // 버튼 클릭 시 텍스트 뷰의 크기를 변경 및 시각적 효과 추가
        changeSizeButton.setOnClickListener(v -> {
            ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();

            if (!isChanged) {
                // 크기 변경
                layoutParams.width = initialWidth + 300; // 너비를 300 증가
                layoutParams.height = initialHeight + 150; // 높이를 150 증가
                textView.setLayoutParams(layoutParams);  // 크기 변경 적용

                // 배경색 변경
                textView.setBackgroundColor(Color.YELLOW); // 배경을 노란색으로 변경

                // 텍스트 크기도 확대
                textView.setTextSize(24);  // 텍스트 크기를 24sp로 설정

                // 상태 변경 표시
                isChanged = true; // 상태를 변경했음을 표시
            } else {
                // 이전 상태로 되돌리기
                layoutParams.width = initialWidth; // 원래 너비로 설정
                layoutParams.height = initialHeight; // 원래 높이로 설정
                textView.setLayoutParams(layoutParams); // 크기 변경 적용

                // 배경색 원래대로 복원
                textView.setBackgroundColor(Color.TRANSPARENT); // 배경을 투명으로 변경

                // 텍스트 크기도 원래대로 설정
                textView.setTextSize(18); // 원래 텍스트 크기인 18sp로 설정

                // 상태 변경 표시
                isChanged = false; // 상태를 되돌렸음을 표시
            }

            // 크기 변경 후 크기 비교를 위해 ViewTreeObserver 사용
            textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    // 변경된 크기 가져오기
                    int newWidth = textView.getWidth();
                    int newHeight = textView.getHeight();

                    // 변경 전후 크기 로그 출력
                    System.out.println("변경 후 크기: " + newWidth + " x " + newHeight);

                    // UI 업데이트: 변경된 크기를 텍스트로 표시
                    textView.setText("현재 크기: " + newWidth + " x " + newHeight);

                    // 리스너 제거 (한 번만 비교하면 되므로)
                    textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }
            });
        });
    }
}

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/myTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="버튼을 클릭하면 뷰 화면의 크기와 색상이 바뀌어요!"
        android:textSize="18sp"
        android:background="#FFDDDDDD"
        android:padding="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/changeSizeButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="크기,색상변경"
        app:layout_constraintTop_toBottomOf="@id/myTextView"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

시연영상