Files
XRLib/Assets/Scripts/NHN/LayoutUpdater.cs

101 lines
4.2 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace Gpm.Ui
{
/// <summary>
/// 이 컴포넌트가 부착된 UI 요소의 크기가 변경될 때, 부모 UI 요소의 레이아웃을 강제로 다시 계산하도록 요청하는 역할을 합니다.
/// 주로 중첩된 레이아웃 그룹(Layout Group)이나 ContentSizeFitter 사용 시, 자식의 크기 변경이 부모에게 제대로 전달되지 않아
/// UI가 깨져 보일 때 사용하면 유용합니다.
/// </summary>
/// <example>
/// <b>UI 계층 구조 예시:</b>
/// <code>
/// - VerticalPanel (VerticalLayoutGroup)
/// - HorizontalPanel (HorizontalLayoutGroup, ContentSizeFitter, LayoutUpdater)
/// - Item1
/// - Item2
/// </code>
/// 위 구조에서 'HorizontalPanel'에 아이템이 추가되어 너비가 변경될 때, 'ContentSizeFitter'가 'HorizontalPanel'의 크기를 조절합니다.
/// 이때 'HorizontalPanel'에 부착된 'LayoutUpdater'는 자신의 크기 변경을 감지하고,
/// 부모인 'VerticalPanel'에게 "자식 크기가 바뀌었으니 너의 레이아웃을 다시 정렬해!"라고 알려주는 역할을 합니다.
/// 결과적으로 'VerticalPanel'은 변경된 'HorizontalPanel'의 크기에 맞춰 레이아웃을 올바르게 갱신하게 됩니다.
/// </example>
[ExecuteAlways] // 에디터 모드에서도 스크립트가 실행되어, UI 변경을 실시간으로 확인할 수 있게 합니다.
[RequireComponent(typeof(RectTransform))] // 이 컴포넌트는 RectTransform이 필수적으로 필요함을 명시합니다.
public class LayoutUpdater : UIBehaviour
{
// 성능 최적화를 위해 부모 RectTransform 컴포넌트를 캐싱하는 변수입니다.
private RectTransform m_Parent;
/// <summary>
/// 이 컴포넌트가 부착된 GameObject의 부모 RectTransform에 대한 참조입니다.
/// </summary>
public RectTransform rectParent
{
get
{
if(m_Parent == null)
{
if(transform.parent != null)
{
m_Parent = transform.parent.GetComponentInParent<RectTransform>();
}
}
return m_Parent;
}
}
/// <summary>
/// 이 컴포넌트가 부착된 RectTransform의 크기나 앵커 등이 변경될 때 호출됩니다.
/// 부모의 레이아웃을 즉시 다시 계산하도록 강제합니다.
/// </summary>
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
SetDirty(true);
}
/// <summary>
/// 부모 레이아웃을 다시 계산해야 함을 시스템에 알립니다.
/// </summary>
/// <param name="force">true일 경우, 즉시 레이아웃을 다시 계산합니다. false일 경우, 다음 프레임에 다시 계산하도록 예약합니다.</param>
protected void SetDirty(bool force = false)
{
RectTransform parent = rectParent;
if (parent == null)
{
return;
}
if (force == true)
{
// 즉시 레이아웃을 강제로 다시 계산합니다.
LayoutRebuilder.ForceRebuildLayoutImmediate(parent);
}
else
{
// 다음 레이아웃 계산 주기에 맞춰 다시 계산하도록 표시만 해둡니다.
LayoutRebuilder.MarkLayoutForRebuild(parent);
}
}
protected override void OnTransformParentChanged()
{
m_Parent = transform.parent.GetComponentInParent<RectTransform>();
}
#if UNITY_EDITOR
/// <summary>
/// (Unity 에디터 전용) 스크립트가 로드되거나 인스펙터에서 값이 변경될 때 호출됩니다.
/// 에디터에서 실시간으로 레이아웃 변경을 확인할 수 있도록 업데이트를 요청합니다.
/// </summary>
protected override void OnValidate()
{
SetDirty(false);
}
#endif
}
}