Version: 2021.3
언어: 한국어
첫 런타임 UI 만들기
레이아웃 엔진

시각적 트리

UI 툴킷의 가장 기본적인 빌딩 블록은 시각적 요소입니다. 시각적 요소는 부모-자식 관계가 있는 계층 구조 트리로 정렬됩니다. 아래 다이어그램은 계층 구조 트리의 단순화된 예와 UI 툴킷의 렌더링된 결과를 보여줍니다.

시각적 트리의 단순화된 계층 구조
시각적 트리의 단순화된 계층 구조

시각적 요소

VisualElement 클래스는 시각적 트리의 모든 노드에 대한 기반입니다. VisualElement 기본 클래스에는 스타일, 레이아웃 데이터, 이벤트 핸들러와 같은 프로퍼티가 포함되어 있습니다. 시각적 요소에는 자식 및 자손 시각적 요소가 있을 수 있습니다. 예를 들어 위 다이어그램에서 첫 번째 Box 시각적 요소에는 Label, Checkbox, Slider라는 세 가지 자식 시각적 요소가 있습니다.

스타일시트를 통해 시각적 요소의 형상을 커스터마이즈할 수 있습니다. 또한 이벤트 콜백을 사용하여 시각적 요소의 동작을 수정할 수도 있습니다.

VisualElement는 컨트롤과 같은 추가 동작 및 기능을 정의하는 서브 클래스로 파생됩니다. UI 툴킷에는 특수 동작이 포함된 다양한 빌트인 컨트롤이 포함되어 있습니다. 예를 들어 다음 항목을 빌트인 컨트롤로 사용할 수 있습니다.

  • 버튼
  • 토글
  • 텍스트 입력 필드

시각적 요소를 서로 결합하고 해당 동작을 수정하여 커스텀 컨트롤을 생성할 수도 있습니다. 빌트인 컨트롤 리스트는 컨트롤 레퍼런스 페이지를 참조하십시오.

패널

패널은 시각적 트리의 부모 오브젝트입니다. 트리 내부의 시각적 요소가 렌더링되려면 시각적 트리가 패널에 연결되어야 합니다. 모든 패널은 에디터 창 또는 런타임 UIDocument에 속합니다. 또한 패널은 포커스 컨트롤 그리고 시각적 트리에 대한 이벤트 디스패치를 처리합니다.

시각적 트리의 모든 요소에는 시각적 트리를 포함하는 패널에 대한 직접 레퍼런스가 있습니다. VisualElement와 패널의 연결을 확인하기 위해 이 요소의 panel 프로퍼티를 테스트할 수 있습니다. 시각적 요소가 연결되지 않은 경우 테스트는 null을 반환합니다.

드로잉 순서

시각적 트리에서 요소의 드로잉 순서는 뎁스 우선 검색을 따릅니다. 자식 시각적 요소는 부모 요소 위에 나타납니다. UI 툴킷은 형제 리스트의 순서로 자식 요소를 그립니다. 드로잉 순서는 다음과 같습니다.

  1. 최상위 시각적 요소
  2. 해당 시각적 요소의 첫 번째 자식 요소
  3. 자손 요소의 자식 요소

아래 다이어그램은 이전 예제의 드로잉 순서를 보여줍니다.

시각적 요소 드로잉 순서
시각적 요소 드로잉 순서

시각적 요소의 드로잉 순서를 변경하려면 다음 함수를 사용하십시오.

형제 시각적 요소의 경우 다음 함수를 사용하십시오.

좌표 및 포지션 시스템

UI 툴킷은 스타일 프로퍼티의 레이아웃 파라미터를 기반으로 개별 요소의 포지션 및 크기를 자동으로 계산하는 강력한 레이아웃 시스템을 사용합니다. 이 레이아웃 시스템은 웹 레이아웃 모델인 Flexbox를 기반으로 합니다. 자세한 내용은 레이아웃 엔진을 참조하십시오.

UI 툴킷에는 다음과 같은 두 가지 타입의 좌표가 있습니다.

  • 상대: 요소의 계산된 포지션을 기준으로 하는 좌표입니다. 레이아웃 시스템은 요소의 포지션을 계산한 후 좌표를 오프셋으로 추가합니다. 자식 요소는 부모 요소의 포지션 및 크기에 영향을 줄 수 있는데, 이는 레이아웃 엔진이 요소 포지션을 계산할 때 고려하기 때문입니다.
  • 절대: 부모 요소를 기준으로 하는 좌표이며, 자동 레이아웃 계산을 우회하고 요소의 포지션을 직접 설정합니다. 같은 부모 아래에 있는 자식 요소는 요소의 포지션에 영향을 주지 않습니다. 이와 마찬가지로, 요소는 동일한 부모 아래에 있는 다른 형제의 포지션 및 크기에 영향을 주지 않습니다.

각 시각적 요소는 위치를 계산하는 데 사용되는 좌표 시스템을 결정합니다. 요소 스타일시트에서 사용할 좌표 시스템을 구성할 수 있습니다.

다음 코드는 코드를 통해 시각적 요소의 포지션 및 좌표 공간을 설정하는 방법을 보여줍니다.

    var newElement = new VisualElement();
        newElement.style.position = Position.Relative;
        newElement.style.left = 15;
        newElement.style.top = 35;

요소의 원점은 왼쪽 상단 코너입니다.

레이아웃 시스템은 각 요소의 VisualElement.layout 프로퍼티(Rect 타입)를 계산하며, 여기에는 요소의 최종 포지션이 포함됩니다. 이때 요소의 상대 또는 절대 포지션이 고려됩니다.

layout.position은 점으로 표현되며, 해당 부모의 좌표 공간을 기준으로 합니다.

VisualElement에는 요소의 포지션 및 회전에 로컬 오프셋을 추가하는 데 사용할 수 있는 트랜스폼 프로퍼티(ITransform)가 있습니다. 오프셋은 계산된 레이아웃 프로퍼티에 표시되지 않습니다. 기본적으로 transform은 ID입니다.

worldBound 프로퍼티를 사용하여 VisualElement의 최종 창 공간 좌표를 검색해서 가져오고, 레이아웃 포지션과 트랜스폼을 모두 고려하십시오. 이 포지션에는 창 헤더의 높이가 포함됩니다.

예제

다음 코드 샘플은 상대 위치 지정과 절대 위치 지정 간의 차이를 보여줍니다. 또한 자동 레이아웃 시스템을 사용하여 창에 상자를 추가하고 해당 포지션을 계산합니다. 한 상자는 25 px의 상대 오프셋을 보여주고, 또 다른 상자는 25 px, 25 px의 절대 포지션을 보여줍니다.

시각적 요소 위치 지정
시각적 요소 위치 지정

이 예제가 동작하는 방식을 확인하려면 다음 단계를 따르십시오.

  1. Assets > Scripts > Editor에서 PositioningTestWindow라는 C# 스크립트를 작성합니다.
  2. 아래 코드를 복사하여 C# 스크립트에 붙여넣습니다.
  3. 에디터 툴바에서 Window > UI Toolkit > Positioning Test Window를 선택합니다.

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public class PositioningTestWindow : EditorWindow
{
    [MenuItem("Window/UI Toolkit/Positioning Test Window")]
    public static void ShowExample()
    {
        var wnd = GetWindow<PositioningTestWindow>();
        wnd.titleContent = new GUIContent("Positioning Test Window");
    }

    public void CreateGUI()
    {
        for (int i = 0; i < 2; i++)
        {
            var temp = new VisualElement();
            temp.style.width = 70;
            temp.style.height = 70;
            temp.style.marginBottom = 2;
            temp.style.backgroundColor = Color.gray;
            rootVisualElement.Add(temp);
        }

        // Relative positioning
        var relative = new Label("Relative\nPos\n25, 0");
        relative.style.width = 70;
        relative.style.height = 70;
        relative.style.left = 25;
        relative.style.marginBottom = 2;
        relative.style.backgroundColor = new Color(0.2165094f, 0, 0.254717f);
        rootVisualElement.Add(relative);

        for (int i = 0; i < 2; i++)
        {
            var temp = new VisualElement();
            temp.style.width = 70;
            temp.style.height = 70;
            temp.style.marginBottom = 2;
            temp.style.backgroundColor = Color.gray;
            rootVisualElement.Add(temp);
        }

        // Absolute positioning
        var absolutePositionElement = new Label("Absolute\nPos\n25, 25");
        absolutePositionElement.style.position = Position.Absolute;
        absolutePositionElement.style.top = 25;
        absolutePositionElement.style.left = 25;
        absolutePositionElement.style.width = 70;
        absolutePositionElement.style.height = 70;
        absolutePositionElement.style.backgroundColor = Color.black;
        rootVisualElement.Add(absolutePositionElement);
    }
}

좌표 시스템 간의 변환

VisualElement.layout.positionVisualElement.transform 프로퍼티는 로컬 좌표 시스템과 부모 좌표 시스템 간의 변환 방식을 정의합니다.

VisualElementExtensions 정적 클래스는 좌표 시스템 간에 점과 사각형을 변환하는 다음의 확장 메서드를 제공합니다.

  • WorldToLocalVector2 또는 RectPanel 공간에서 요소 내 레퍼렌셜로 변환합니다.
  • LocalToWorldVector2 또는 RectPanel 공간 레퍼렌셜로 변환합니다.
  • ChangeCoordinatesTo는 한 요소의 로컬 공간에 있는 Vector2 또는 Rect를 다른 로컬 공간으로 변환합니다.
첫 런타임 UI 만들기
레이아웃 엔진