using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace Gpm.Ui
{
///
/// 이 컴포넌트가 부착된 RectTransform의 크기가 변경될 때, 지정된 'target' RectTransform들의 크기를 동일하게 맞추는 역할을 합니다.
/// 주로 ContentSizeFitter와 함께 사용되어 동적으로 변하는 콘텐츠의 크기에 맞춰 배경 이미지 등의 크기를 조절할 때 유용합니다.
///
///
/// UI 계층 구조 예시:
///
/// - Background (RectTransform)
/// - Content (RectTransform, VerticalLayoutGroup, ContentSizeFitter, ContentSizeSetter)
/// - Item1 (Image)
/// - Item2 (Image)
/// - ...
///
/// 위와 같은 구조에서 'Content' GameObject에 이 스크립트를 추가하고,
/// 'target' 배열에 'Background'의 RectTransform을 할당하면,
/// 'Content'의 크기가 내부 아이템(Item1, Item2)에 의해 변경될 때마다 'Background'의 크기도 함께 조절됩니다.
///
[ExecuteAlways] // 에디터 모드에서도 스크립트가 실행되도록 하여, UI 변경을 실시간으로 확인할 수 있게 합니다.
[RequireComponent(typeof(RectTransform))] // 이 컴포넌트는 RectTransform이 필수적으로 필요함을 명시합니다.
public class ContentSizeSetter : UIBehaviour
{
// 성능 최적화를 위해 RectTransform 컴포넌트를 캐싱하는 변수입니다.
[System.NonSerialized]
private RectTransform m_Rect;
///
/// 이 컴포넌트가 부착된 GameObject의 RectTransform에 대한 참조입니다.
/// 처음 접근할 때 GetComponent를 통해 초기화하고, 이후에는 캐시된 값을 사용합니다.
///
private RectTransform rectTransform
{
get
{
if (m_Rect == null)
{
m_Rect = GetComponent();
}
return m_Rect;
}
}
///
/// 크기를 조절할 때 추가할 여백(margin)입니다.
/// x, y 값을 설정하여 target의 너비와 높이에 각각 추가적인 공간을 줄 수 있습니다.
///
public Vector2 margin;
///
/// 이 컴포넌트의 크기에 맞춰 함께 크기가 조절될 RectTransform(들)의 배열입니다.
/// 인스펙터 창에서 크기를 동기화할 UI 요소들을 여기에 할당합니다.
///
public RectTransform[] target;
///
/// 컴포넌트가 활성화될 때 호출되는 Unity 생명주기 함수입니다.
/// 레이아웃을 다시 계산하도록 시스템에 요청합니다.
///
protected override void OnEnable()
{
SetDirty();
}
///
/// 이 컴포넌트가 부착된 RectTransform의 크기나 앵커 등이 변경될 때 호출됩니다.
/// 이 스크립트의 핵심 로직으로, target 배열에 있는 모든 RectTransform의 크기를 현재 RectTransform의 크기에 맞게 업데이트합니다.
///
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
// 현재 RectTransform의 크기에 margin 값을 더하여 최종 크기를 계산합니다.
Vector2 sizeDelta = new Vector2(rectTransform.sizeDelta.x + margin.x, rectTransform.sizeDelta.y + margin.y);
if (target != null)
{
// target 배열의 모든 RectTransform에 대해 계산된 크기를 적용합니다.
for (int i = 0; i < target.Length; i++)
{
target[i].sizeDelta = sizeDelta;
// target의 레이아웃을 갱신하도록 표시하여 UI가 올바르게 다시 그려지도록 합니다.
LayoutRebuilder.MarkLayoutForRebuild(target[i]);
}
}
}
///
/// UI 레이아웃을 다시 계산해야 함을 시스템에 알립니다.
///
/// true일 경우, 즉시 레이아웃을 다시 계산합니다. false일 경우, 다음 프레임에 다시 계산하도록 예약합니다.
protected void SetDirty(bool force = false)
{
if (IsActive() == false)
{
return;
}
if (force == true)
{
// 즉시 레이아웃을 강제로 다시 계산합니다.
LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);
}
else
{
// 다음 레이아웃 계산 주기에 맞춰 다시 계산하도록 표시만 해둡니다. (일반적인 경우)
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
}
}
#if UNITY_EDITOR
///
/// (Unity 에디터 전용) 스크립트가 로드되거나 인스펙터에서 값이 변경될 때 호출됩니다.
/// 에디터에서 margin과 같은 값을 변경했을 때, 실시간으로 UI에 반영되도록 레이아웃 업데이트를 요청합니다.
///
protected override void OnValidate()
{
SetDirty(false);
}
#endif
}
}