앱 개발/Unity, C#

[Unity][UI Toolkit] uss에서 gap 옵션(child 사이 spacing) 구현하기 [USS]

마라턍 2024. 11. 29. 20:37

uss는 css처럼 유니티 UI Toolkit에서 스타일을 적용시킬 때 사용한다.

웹 형식과 비슷해 더욱 쉽게 디자인할 수 있다는 장점이 있지만,

아직 개발 단계라 css에서 제공하는 속성 중 적용되지 않는 것(line-height, gap 등)이 있다는 것이 단점이다.

 

특히, 웹을 할 때는 css에서 flex 속성과 함께 gap 속성을 주면 자식 요소를 간단하고 깔끔하게 정렬할 수 있었는데

유니티 uss에는 해당 속성이 없어서 자식의 margin을 하나씩 다 설정해줘야 한다. (아래의 css 코드처럼 말이다)

div > *:not(:last-child) {
    display: block;
    margin-bottom: 20px;
}

 

그런데 문제는, uss가 not 선택자는 물론 last-child 선택자도 지원하지 않는다.

그래서 child의 margin을 자동으로 조정하여 css의 gap 효과를 구현할 수 있는 VisualElement 코드를 작성해보았다.

 

ChildAnnotator (first-child, last-child)

해당 코드에는 ChildAnnotator가 등장하는데, 이건 first-child와 last-child 클래스를 자동으로 추가해줌으로써

uss에서도 css의 first-child와 last-child 선택자를 비슷하게나마 사용할 수 있도록 하는 스크립트다.

자세한 내용은 아래의 포스팅 참고.

 

[Unity][UI Toolkit] uss에서 first-child, last-child 구현하기 [USS]

UI Toolkit -> UGUI (Nova) -> 다시 UI Toolkit으로 migration 하는 중...유니티 버전을 2021에서 2022로 업그레이드 하면서 UI Toolkit도 많이 안정되었구나 싶긴 했는데,그래도 여전히 기존 css에서 구현되는 기능

hotsunchip.tistory.com

 

 

코드

GapContainer은 ChildAnnotator을 상속 받아, last-child를 제외하고 gap 값만큼 child의 margin-right 또는 margin-bottom 값을 자동으로 설정해도록 작성하였다.

더보기
using UnityEngine.Scripting;
using UnityEngine.UIElements;

namespace UI.Common
{
  public class GapContainer : ChildAnnotator
  {
    private int gapX { get; set; }
    private int gapY { get; set; }

    protected override void OnChildChange(ChildChangeEvent evt)
    {
      base.OnChildChange(evt);
      
      UpdateChildMargins();
    }

    private void UpdateChildMargins()
    {
      for (var i = 0; i < childCount; i++)
      {
        var child = this[i];
        child.style.marginRight = child == lastChild ? 0 : gapX;
        child.style.marginBottom = child == lastChild ? 0 : gapY;
      }
    }

    [Preserve]
    public new class UxmlFactory : UxmlFactory<GapContainer, UxmlTraits> { }

    [Preserve]
    public new class UxmlTraits : VisualElement.UxmlTraits {
      private readonly UxmlIntAttributeDescription checkInterval = new UxmlIntAttributeDescription { name = "check-interval", defaultValue = 0 };
      private readonly UxmlIntAttributeDescription gapXAttribute = new UxmlIntAttributeDescription { name = "gap-x", defaultValue = 0 };
      private readonly UxmlIntAttributeDescription gapYAttribute = new UxmlIntAttributeDescription { name = "gap-y", defaultValue = 0 };

      public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) {
        base.Init(ve, bag, cc);
        var item = (GapContainer) ve;

        item.childChanger.checkInterval = checkInterval.GetValueFromBag(bag, cc);

        item.gapX = gapXAttribute.GetValueFromBag(bag, cc);
        item.gapY = gapYAttribute.GetValueFromBag(bag, cc);
      }
    }
  }
}

 

 

적용 결과

GapContainer을 이용하여 child의 margin을 조정하여 css의 gap 속성을 구현함

  • Gap X: child 사이의 x축 방향 거리를 px 단위로 할당
  • Gap Y: child 사이의 y축 방향 거리를 px 단위로 할당

후딱 간단하게 짠 거라 GapContainer 내에 있던 element가 밖으로 나간 경우 등의 상황은 고려되어 있지 않지만,

그래도 필요한 사람이 있을 것 같아 스리슬쩍 공유해봅니다..

child의 width(가로 정렬 시) 또는 height(세로 정렬 시)에 사용하기 적합하며, 그 이외의 경우에는 각 child마다의 크기가 달라질 수 있다는 것만 유의해주십셔

그리고 이 코드에서 더 나아가서 코드를 발전시키셨다면 어떻게 하셨는지 공유해주시면 큰 도움이 될 것 같습니다..!

 

아 참고로 전 유니티 2022.3.45f1 버전 사용 중입니다.

 

 

끗~