안드로이드 자바

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

teamnova 2024. 11. 4. 12:00
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>

 

시연영상