유니티 UI 앵커 배치 작업 시간을 줄이기 위한 자동화 코드

2026. 2. 27. 13:22·기능 구현 방법 정리

이전에 해상도에 따른 UI 작업을 다룬 포스팅이 있었는데,

앵커를 통해 화면 일정 비율 위치에 UI를 배치하는 방법에 대해 소개를 드렸습니다.

 

https://ybbro.tistory.com/27

 

하지만, 그 작업을 모든 UI에 하나하나 하고 있다면 시간 소모가 매우 커집니다.

따라서 그 작업을 자동화하여 아주 빠르고 간단히 진행할 수 있는 에디터 메뉴를 만들었기에 공유드립니다.

 

<< 적용 전 >>

<< 적용 후 >>

 

 

<< 주의사항 >>

1. 해당 스크립트를 만들어 Assets/Editor 폴더에 넣어주시고 주석으로 된 사용법을 따라해보세요.

2. Grid / Vertical / Horizontal Layout Group, ContentSizeFitter 과 같은 자동 정렬 컴포넌트는 계산을 덮어써 비율이 깨지기에 정렬 대상에서 제외되도록 처리해 두었습니다. >> 해당 오브젝트들은 Canvas Scaler의 Match를 조절하여 최대한 맞춰봅시다.

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

public class RectTransformAnchorSetter
{
    // 1. 목적
    // 캔버스 스케일러 - UI 스케일 모드를 쓰더라도 기준 화면 비율과 다르게 되면 깨질 수 있음 (pc에서의 창 크기 조절 or 모바일 폰 해상도 비율 다름 등)
    // UI 작업 때 시간이 오래 걸림 + 이후 수정해야 할 수 있어 앵커를 다 맞춰주지는 않는데,
    // 화면 비율이 달라지면 해당 UI들이 의도한 것과 다르게 배치되는 경우가 있기에
    // 현재 위치를 앵커로 마킹한 후 포지션을 0으로 만들어 그 화면 위치 비율에 고정시키는 작업을 하나하나 수작업 해줘야 하는 2차 수고 발생
    // 그 작업 시간을 획기적으로 줄이기 위해 자동화 메뉴를 만들었습니다.

    // 2. 사용법
    // 1) 하이어라키를 전체 선택(단축키 Ctrl + A) (UI가 아닌 요소들은 자동으로 걸러주기에 전체 선택)
    // 2) 유니티 에디터 상단 메뉴 - Tools - UI - Set Anchors To Current Rect 메뉴(단축키 Ctrl + Shift + Q)

    // 메뉴에 항목 추가
    // %#q = Ctrl + Shift + Q 단축키
    [MenuItem("Tools/UI/Set Anchors To Current Rect %#q")] 
    static void SetAnchorsToSelectedRect()
    {
        Canvas.ForceUpdateCanvases();

        // 앵커 프리셋 Middle, Center 설정용
        Vector2 anchorPreset_MiddleCenter = new Vector2(0.5f, 0.5f);

        // 선택된 모든 오브젝트 순회
        foreach (var obj in Selection.gameObjects)
        {
            // RectTransform 컴포넌트 가져오기
            RectTransform rect = obj.GetComponent<RectTransform>();
            // RectTransform이 아니거나 앵커의 기준이 될 부모가 없으면 제외
            if (rect == null || rect.parent == null)
                continue;

            // UI 요소들은 Canvas (RectTransform 포함)의 자식이며 그 안의 요소들도 RectTransform으로 위치 결정
            // 부모도 RectTransform이어야 계산 가능 >> 앵커의 기준
            RectTransform parentRect = rect.parent as RectTransform;
            if (parentRect == null)
                continue;

            // 슬라이더의 자식 오브젝트를 자동 앵커로 하면 Fill, Handle이 깨짐
            // 슬라이더 컴포넌트가 들어간 오브젝트만 앵커를 맞춰주면 그 자식들은 자동으로 부모에 맞춰짐
            Slider slider = rect.GetComponent<Slider>();
            Slider parentSlider = rect.GetComponentInParent<Slider>(true);
            if (parentSlider != null && slider != parentSlider)
            {
                Debug.LogWarning($"{obj.name} 계산 건너뜀.\n원인: 부모에 슬라이더 존재하여 계산 불필요");
                continue;
            }

            // ContentSizeFitter 컴포넌트가 있는 요소 제외 >> preferred size 기준 RectTransform.sizeDelta 강제 조절 >> 앵커 기반 계산과 충돌하여 비율 어긋남
            // >> 다른 컴포넌트나 스크립트에서 위치 계산을 다시해서 덮어쓰면 해당 변환을 수행해서는 안됨. 이하 레이아웃 그룹 제외도 같은 이유
            if (rect.GetComponent<ContentSizeFitter>() != null)
            {
                Debug.LogWarning($"{obj.name} 계산 건너뜀.\n원인: ContentSizeFitter에서 위치 자동 계산");
                continue;
            }

            // Layout 시스템에 의해 제어되는 요소 제외. 단 GetComponentInParent이 해당 탐색을 수행하는 자신도 포함인데, 레이아웃 그룹 컴포넌트가 있는 부모는 앵커 위치 고정을 해줘야 잘 맞음
            LayoutGroup layoutGroup = rect.GetComponent<LayoutGroup>();
            LayoutGroup layoutGroup_Parent = rect.GetComponentInParent<LayoutGroup>(true);
            if (layoutGroup_Parent != null && layoutGroup != layoutGroup_Parent)
            {
                Debug.LogWarning($"{obj.name} 계산 건너뜀.\n원인: LayoutGroup이 있는 오브젝트의 자식이므로 위치 자동 계산");
                continue;
            }

            // Undo 기록 (Ctrl+Z로 되돌리기 가능하게)
            Undo.RecordObject(rect, "Set Anchors");

            /*
             핵심 개념 설명
             
             offsetMin = 왼쪽 아래 기준 앵커로부터 얼마나 떨어져 있는지 (픽셀)
             offsetMax = 오른쪽 위 기준 앵커로부터 얼마나 떨어져 있는지 (픽셀)

             우리는 이 offset을 부모 크기로 나눠서
             "비율"로 변환 후 anchor에 더해줄 것이다.
            */

            // 부모의 실제 너비/높이
            float parentWidth = parentRect.rect.width;
            float parentHeight = parentRect.rect.height;

            // 0 나누기 방지: 부모 크기가 0이면 계산이 불가능하므로 로그를 남기고 스킵
            // >> 자동으로 맞춰주면 문제 발생 우려가 있기에 작업자에게 알림
            if (Mathf.Approximately(parentWidth, 0) || Mathf.Approximately(parentHeight, 0))
            {
                Debug.LogWarning($"{obj.name} 계산 건너뜀.\n원인: 부모 {parentRect.name}의 Width 혹은 Height가 0. 해당 값을 0보다 큰 값으로 바꾼 후 다시 실행");
                continue;
            }

            // 현재 offset을 부모 크기 기준 비율로 변환
            Vector2 newAnchorMin = new Vector2(
                rect.anchorMin.x + rect.offsetMin.x / parentWidth,
                rect.anchorMin.y + rect.offsetMin.y / parentHeight
            );

            Vector2 newAnchorMax = new Vector2(
                rect.anchorMax.x + rect.offsetMax.x / parentWidth,
                rect.anchorMax.y + rect.offsetMax.y / parentHeight
            );

            // 새 앵커 적용
            rect.anchorMin = newAnchorMin;
            rect.anchorMax = newAnchorMax;

            /*
             이제 offset을 anchor에 흡수했으므로
             offset은 0으로 만들어도
             화면상 위치/크기는 그대로 유지된다.
            */
            rect.offsetMin = Vector2.zero;
            rect.offsetMax = Vector2.zero;
        }
    }
}
#endif
저작자표시 비영리 동일조건 (새창열림)

'기능 구현 방법 정리' 카테고리의 다른 글

유니티, C#) AES 암호화/복호화 + JSON 데이터 저장/불러오기  (0) 2025.02.10
유니티 UI 이미지 마스크  (0) 2025.01.27
유니티 UI에 스파인 애니메이션 넣기  (0) 2025.01.26
유니티 2D) 부모 오브젝트 주위를 자식 오브젝트들이 원형으로 회전하게 하고 싶다면? (RotateAround 사용 버전도 포함)  (0) 2024.12.12
유니티) 레이어마스크(LayerMask) 사용법, 2D 가장 가까운 적 탐색  (0) 2024.12.02
'기능 구현 방법 정리' 카테고리의 다른 글
  • 유니티, C#) AES 암호화/복호화 + JSON 데이터 저장/불러오기
  • 유니티 UI 이미지 마스크
  • 유니티 UI에 스파인 애니메이션 넣기
  • 유니티 2D) 부모 오브젝트 주위를 자식 오브젝트들이 원형으로 회전하게 하고 싶다면? (RotateAround 사용 버전도 포함)
ybbro
ybbro
대부분의 포스팅은 pc에서 작성되었습니다. 모바일에서 볼 때 설명이 잘리면 데스크탑 모드를 사용해보길 바랍니다.
  • ybbro
    어떻게든 굴리는 게임 공방
    ybbro
  • 전체
    오늘
    어제
    • 전체 N
      • 스파르타코딩클럽_Unity개발과정
      • Unity 2D
        • 카드게임
        • 플랫포머 게임
        • 뱀서라이크
      • Unity 3D
        • 닷지
        • 유니티 짱
        • 디펜스 게임
        • Inkoid
      • Unity 에러 노트
      • 기능 구현 방법 정리
      • 셰이더 그래프
        • 2D
        • 3D
      • 프로그래머스
      • 자료구조
      • 기타
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    hello
    유니티 애니메이터 파라미터 초기화
    스파인
    무료스킨
    룰렛
    대시
    sprite mask
    텍스트매시프로
    UI
    다크모드
    세이브
    unity
    유니티
    삭제
    마스크
    갤럭시 S24
    앱이 휴대전화와 호환되지 않아 설치되지 않았습니다
    64비트
    잔상
    직렬화
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
ybbro
유니티 UI 앵커 배치 작업 시간을 줄이기 위한 자동화 코드
상단으로

티스토리툴바