Version: 2018.4
레이아웃 엔진
UXML 템플릿 작성

UXML 포맷

UXML 파일은 사용자 인터페이스의 논리 구조를 정의하는 텍스트 파일입니다. 이 UXML 파일에서 사용되는 포맷은 HTML(HyperText Markup Language), XAML(eXtensible Application Markup Language), XML(eXtensible Markup Language)의 영감을 받았습니다. 이러한 잘 알려진 포맷에 익숙하다면 UXML에서 많은 공통점을 찾아볼 수 있습니다. 하지만 UXML 포맷에는 Unity 작업의 효율을 높여주는 작은 차이점들이 있습니다.

이 섹션에서는 Unity에서 지원하는 UXML 포맷을 설명하고, UXML 템플릿을 작성, 로드 및 정의하는 방법에 대한 상세 정보를 제공합니다. 또한 새로운 요소를 정의하고 UQuery를 정의하는 방법도 함께 소개합니다.

UXML은 기술 숙련도가 낮은 사용자들이 Unity로 사용자 인터페이스를 쉽게 빌드하도록 도와줍니다. UXML은 다음의 기능을 제공합니다.

  • 사용자 인터페이스(UI)의 구조를 XML로 정의합니다.
  • USS 스타일시트로 UI 레이아웃을 정의합니다.

이 경우 개발자들이 에셋 임포트, 로직 정의 및 데이터 처리 같은 기술 작업을 직접 수행해야 합니다.

새로운 요소 정의

UIElements는 확장이 가능하므로 개발자들은 고유한 사용자 인터페이스 컴포넌트와 요소를 정의할 수 있습니다.

UXML 파일을 사용하여 새로운 요소를 정의하기 전에 VisualElement 또는 해당 서브 클래스 중 하나에서 새로운 클래스를 파생한 후 새로운 클래스 안에 적절한 기능을 구현해야 합니다. 새로운 클래스는 반드시 기본 생성자를 구현해야 합니다.

예를 들어, 다음 코드는 새로운 StatusBar 클래스를 파생하고 해당 기본 생성자를 구현합니다.

class StatusBar : VisualElement
{
    public StatusBar()
    {
        m_Status = String.Empty;
    }

    string m_Status;
    public string status { get; }
}

UXML 파일을 읽을 때 UIElements가 새로운 클래스를 인스턴스화할 수 있도록 만들려면 클래스에 대해 팩토리를 정의해야 합니다. 팩토리가 특별한 작업을 할 필요가 없는 경우에는 UxmlFactoy<T>에서 팩토리를 파생할 수 있습니다. 또한 팩토리 클래스는 컴포넌트 클래스 안에 배치하는 것이 좋습니다.

예를 들어 다음 코드는 UxmlFactory<T>에서 StatusBar 클래스의 팩토리를 파생하여 해당 클래스에 대한 팩토리를 정의하는 방법을 보여줍니다. 팩토리에는 Factory라는 이름이 지정됩니다.

class StatusBar : VisualElement
{
    public new class Factory : UxmlFactory<StatusBar> {}

    // ...
}

이 팩토리를 정의하고 나면 UXML 파일에서 <StatusBar> 요소를 사용할 수 있습니다.

참고: 팩토리는 2018.2에서 개선되었습니다. 이전 버전에서 팩토리를 정의했다면 현재는 지원이 중단된 API를 사용하지 않도록 해당 팩토리를 2018.3으로 이식해야 합니다.

요소에 대한 속성 정의

새로운 클래스에 대해 UXML 특성을 정의하고 해당 팩토리가 그러한 특성을 사용하도록 설정할 수 있습니다.

예를 들어 다음 코드는 UXML 특성 클래스를 정의하여 status 프로퍼티를 StatusBar 클래스의 프로퍼티로 초기화하는 방법을 보여줍니다. 상태 프로퍼티는 XML 데이터에서 초기화됩니다.

class StatusBar : VisualElement
{
    public new class Factory : UxmlFactory<StatusBar, UxmlTraits> {}

    public new class Traits : base.UxmlTraits
    {
        UxmlStringAttributeDescription m_Status = new UxmlStringAttributeDescription { name = "status" };

        public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
        {
            get { yield break; }
        }

        public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
        {
            base.Init(ve, bag, cc);
            ((StatusBar)ve).status = m_Status.GetValueFromBag(bag, cc);
        }
    }

    // ...
}

UxmlTraits는 다음의 두 가지 역할을 수행합니다.

  • 팩토리가 새로 생성된 오브젝트를 초기화하는 데 사용합니다.

  • 스키마 생성 프로세스가 요소에 대한 정보를 가져오기 위해 분석합니다. 이 정보는 XML 스키마 지시문으로 변환됩니다.

위 코드 예제는 다음을 수행합니다.

  • m_Status 선언은 status라는 이름의 XML 속성을 정의합니다.
  • uxmlChildElementsDescriptionStatusBar 요소에 자식이 없음을 의미하는 빈 IEnumerable을 반환합니다.
  • Init() 멤버는 XML 파서의 프로퍼티 백에 있는 status 속성의 값을 읽은 후 StatusBar.status 프로퍼티를 이 값으로 설정합니다.
  • UxmlTraits 클래스를 StatusBar 클래스 내부에 배치하여 Init() 메서드가 StatusBar의 프라이빗 멤버에 액세스하도록 허용합니다.
  • 새로운 UxmlTraits 클래스는 UxmlTraits 기본 클래스에서 상속되기 때문에 기본 클래스의 속성을 공유합니다.
  • Init()base.Init()를 호출하여 기본 클래스 프로퍼티를 초기화합니다.

위 코드 예제는 UxmlStringAttributeDescription 클래스로 문자열 속성을 선언합니다. UIElements는 다음 타입의 속성을 지원하며 각각 C# 타입을 XML 타입에 연결합니다.

  • UxmlStringAttributeDescription: 속성 값은 문자열입니다.
  • UxmlFloatAttributeDescription: 속성 값은 C# float 타입의 범위 내에 있는 하나의 정밀도 부동 소수점 값이어야 합니다.
  • UxmlDoubleAttributeDescription: 속성 값은 C# double 타입의 범위 내에 있는 이중 정밀도 부동 소수점 값이어야 합니다.
  • UxmlIntAttributeDescription: 속성 값은 C# int 타입의 범위 내에 있는 정수 값이어야 합니다.
  • UxmlLongAttributeDescription: 속성 값은 C# long 타입의 범위 내에 있는 긴 정수 값이어야 합니다.
  • UxmlBoolAttributeDescription: 속성 값은 true 또는 false여야 합니다.
  • UxmlColorAttributeDescription: 속성 값은 컬러를 나타내는 문자열(#FFFFFF)이어야 합니다.
  • UxmlEnumAttributeDescription<T> 속성 값은 Enum 타입 T에 대한 값 중 하나를 나타내는 문자열이어야 합니다.

위 코드 예제에서 uxmlChildElementsDescription은 빈 IEnumerable을 반환하며, 이는 StatusBar 요소가 자식을 허용하지 않음을 의미합니다.

요소가 모든 타입의 자식을 허용하도록 만들려면 uxmlChildElementsDescription 프로퍼티를 오버라이드해야 합니다. 예를 들어 StatusBar 요소가 모든 타입의 자식을 허용하려면 uxmlChildElementsDescription 프로퍼티를 다음과 같이 지정해야 합니다.

public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
    get
    {
        yield return new UxmlChildElementDescription(typeof(VisualElement));
    }
}

네임스페이스 접두사 정의

C#으로 새 요소를 정의하고 나면 UXML 파일에서 해당 요소를 사용할 수 있습니다. 새 요소가 새로운 네임스페이스로 정의된 경우 해당 네임스페이스에 대한 접두사를 정의해야 합니다. 네임스페이스 접두사는 속성으로 루트 <UXML> 요소에 대해 선언되고, 요소 범위 지정 시 전체 네임스페이스 이름을 대체합니다.

네임스페이스 접두사를 정의하려면 UxmlNamespacePrefix` 속성을 정의하려는 각 네임스페이스 접두사의 어셈블리에 추가하십시오.

[assembly: UxmlNamespacePrefix("My.First.Namespace", "first")]
[assembly: UxmlNamespacePrefix("My.Second.Namespace", "second")]

이 작업은 어셈블리 C# 파일의 루트 수준(모든 네임스페이스 외부)에서 수행할 수 있습니다.

이 스키마 생성 시스템은 다음을 수행합니다.

  • 이러한 속성에 대한 검사를 수행하고, 속성을 사용하여 스키마를 생성합니다.
  • 네임스페이스 접두사 정의를 새로 생성된 UXML 파일에 있는 <UXML> 요소의 속성으로 추가합니다.
  • xsi:schemaLocation 속성의 네임스페이스에 대한 스키마 파일 위치를 포함합니다.

프로젝트의 UXML 스키마를 업데이트해야 합니다. Assets > Update UIElements Schema를 선택하여 텍스트 편집기가 새 요소를 인식하는지 확인하십시오.

고급 사용

UXML 이름 커스터마이즈

IUxmlFactory.uxmlNameIUXmlFactory.uxmlQualifiedName 프로퍼티를 오버라이드하여 UXML 이름을 커스터마이즈할 수 있습니다. uxmlName이 네임스페이스 내에서 고유한 이름이고, uxmlQualifiedName이 프로젝트 내에서 고유한 이름이어야 합니다.

두 이름 모두가 고유하지 않으면 어셈블리를 로드하려고 할 때 예외가 발생합니다.

다음 코드 예제는 UXML 이름을 오버라이드하고 커스터마이즈하는 방법을 보여줍니다.

public class FactoryWithCustomName : UxmlFactory<..., ...>
{
    public override string uxmlName
    {
        get { return "UniqueName"; }
    }

    public override string uxmlQualifiedName
    {
        get { return uxmlNamespace + "." + uxmlName; }
    }
}

요소에 대한 팩토리 선택

기본적으로 IUxmlFactory는 요소를 인스턴스화하고, 요소 이름을 사용하여 요소를 선택합니다.

IUXmlFactory.AcceptsAttributeBag을 오버라이드하여 선택 프로세스가 요소의 속성 값을 고려하도록 만들 수 있습니다. 그러면 팩토리는 요소 속성을 검사하여 UXML 요소의 오브젝트를 인스턴스화할 수 있는지 결정합니다.

이는 VisualElement 클래스가 일반인 경우에 특히 유용합니다. 이 경우 클래스의 전문화를 위한 클래스 팩토리가 XML type 속성의 값을 검사할 수 있습니다. 해당 값에 따라 인스턴스화가 허용되거나 거절될 수 있습니다. 예제는 PropertyControl<T> 구현을 참조하십시오.

두 개 이상의 팩토리가 요소를 인스턴스화할 수 있는 경우에는 첫 번째로 등록된 팩토리가 선택됩니다.

기본 클래스 속성의 기본 값 오버라이드

파생된 UxmlTraits 클래스에서 defaultValue를 설정하여 기본 클래스에서 선언된 속성의 기본 값을 변경할 수 있습니다.

예를 들어 다음 코드는 m_focusIndex의 기본 값을 변경하는 방법을 보여줍니다.

class MyElementTraits : VisualElementUxmlTraits
    {
        public Traits()
        {
            m_focusIndex.defaultValue = 0;
        }
    }

속성 허용

기본적으로 생성된 XML 스키마는 요소가 모든 속성을 가질 수 있다고 명시합니다.

UxmlTraits 클래스에서 선언된 속성을 제외한 속성 값은 제한되지 않습니다. 이는 선언된 속성의 값이 해당 선언과 일치하는지 확인하는 XML 검증기와 대조됩니다.

추가 속성을 IUxmlAttributes 백에 포함하여 IUxmlFactory.AcceptsAttributBag()IUxmlFactory.Init() 함수에 전달할 수 있습니다. 이러한 추가 속성의 사용 여부는 팩토리 구현에 따라 달라집니다. 기본 동작은 추가 속성을 버리는 것입니다.

즉, 이러한 추가 속성들은 인스턴스화된 VisualElement에 연결되지 않으며 UQuery를 사용하여 쿼리할 수 없습니다.

새 요소를 정의할 때 UxmlTraits 생성자에서 UxmlTraits.canHaveAnyAttribute 프로퍼티를 false로 설정하여 허용되는 속성을 명시적으로 선언된 속성으로만 제한할 수 있습니다.

스키마 정의 사용

스키마 정의 파일은 속성, 그리고 각 UXML 요소가 포함할 수 있는 자식 요소를 지정합니다. 스키마 정의 파일을 가이드로 사용하여 올바른 문서를 작성하고 문서의 유효성을 확인하십시오.

UXML 템플릿 파일에서 <UXML> 루트 요소의 xsi:noNamespaceSchemaLocationxsi:schemaLocation 속성은 스키마 정의 파일의 위치를 지정합니다.

Assets > Create > UIElements View 메뉴 항목을 선택하여 프로젝트에서 사용하는 VisualElement 서브 클래스에서 얻은 최신 정보로 스키마 정의를 자동으로 업데이트하십시오. UXML 스키마 파일을 강제로 업데이트하려면 Assets > Update UIElements Schema를 선택하십시오.

참고: 일부 텍스트 편집기는 xsi:noNamespaceSchemaLocation 속성을 인식하지 않습니다. 텍스트 편집기가 스키마 정의 파일을 찾지 못하면 xsi:schemaLocation 속성도 지정해 주어야 합니다.


  • 2018–11–02 일부 편집 리뷰를 거쳐 페이지 수정됨
레이아웃 엔진
UXML 템플릿 작성