유니티 Custom Grid Layout 만들기

(좌) 유니티 Grid Layout Group / (우) Custom Grid Layout

 

유니티에서도 Grid Layout Group 컴포넌트가 존재하긴 합니다. 하지만 해당 컴포넌트를 사용하면 각 행과 열의 Element이 Grid 형태에서 벗어나지 못한다는 문제가 있습니다(뭔 소리야 ㅋㅋ..그러려고 Grid Layout Group 컴포넌트 쓰는건데!)

 

워워... 그 뜻이 아니라 Grid란 사전 의미를 찾아보면 다음과 같습니다.

수평선과 수직선이 교차해서 이루어진 집합체이다. 하나의 집합체는 세로 열을 그리고 다른 하나는 가로 행을 정의합니다. 각 요소는 이러한 열과 행으로 된 라인으로 배치할 수 있다.

 

즉, 위와 같은 조건을 충족만 하면 Grid라 할 수 있는거죠. 유니티의 Grid Layout Group 컴포넌트는 Grid 조건을 만족하지만 정해져 있는 모습을 벗어나지 못한다는 점입니다...

 

각 행의 Element개수를 다르게 하거나 각 행마다 margin, Spacing을 다르게 할 수 없다는 뜻이죠!

그래서 Custom Grid Layout 컴포넌트를 제작해봤습니다.


Custom Grid Layout

Custom Grid Layout 결과

 

Custom Grid Layout 컴포넌트를 사용하면 위 사진과 같이 각 행의 Element들을 컨트롤 할 수 있습니다.

Spacing과 Margin값이 큰 이유로는.. Rect Transform의 Width와 Height를 너무 작게 설정해서 그런거긴 합니다.

 


코드

using UnityEngine;


    public enum AnchorPoint
    {
        TopLeft,
        MiddleCenter
    }

    public class CustomGridLayout : MonoBehaviour
    {
        public int Rows;
        public int[] ElementsPerRow;
        public Vector2[] Spacing;
        public Vector2[] Margin;
        public AnchorPoint anchorPoint;

        public Vector2 Offset;
        private RectTransform rectTransform;

        private void Start()
        {
            rectTransform = GetComponent<RectTransform>();
            ArrangeElements();
        }

        public void ArrangeElements()
        {
            int childCount = transform.childCount;

            if (ElementsPerRow.Length != Rows || Spacing.Length != Rows || Margin.Length != Rows)
            {
                Debug.LogError("ElementsPerRow, Spacing, Margin arrays must have the same length as Rows.");
                return;
            }

            float containerWidth = rectTransform.rect.width;
            float containerHeight = rectTransform.rect.height;

            int currentElement = 0;

            for (int row = 0; row < Rows; row++)
            {
                int elementsInThisRow = ElementsPerRow[row];
                if (elementsInThisRow == 0) continue;

                float totalSpacingX = (elementsInThisRow - 1) * Spacing[row].x;
                float totalMarginX = Margin[row].x * 2;
                float elementWidth = (containerWidth - totalSpacingX - totalMarginX) / elementsInThisRow;

                float elementHeight = 0;
                for (int i = currentElement; i < currentElement + elementsInThisRow && i < childCount; i++)
                {
                    RectTransform childRect = transform.GetChild(i).GetComponent<RectTransform>();
                    if (childRect.rect.height > elementHeight)
                    {
                        elementHeight = childRect.rect.height;
                    }
                }

                float totalSpacingY = (Rows - 1) * Spacing[row].y;
                float totalMarginY = Margin[row].y * 2;
                float rowHeight = elementHeight + totalSpacingY + totalMarginY;

                for (int col = 0; col < elementsInThisRow; col++)
                {
                    if (currentElement >= childCount)
                    {
                        return;
                    }

                    Transform child = transform.GetChild(currentElement);
                    RectTransform childRect = child.GetComponent<RectTransform>();

                    float xPos = Margin[row].x + col * (elementWidth + Spacing[row].x);
                    float yPos = 0;

                    switch (anchorPoint)
                    {
                        case AnchorPoint.TopLeft:
                            yPos = -Margin[row].y - row * (rowHeight + Spacing[row].y);
                            break;
                        case AnchorPoint.MiddleCenter:
                            yPos = containerHeight / 2 - Margin[row].y - row * (rowHeight + Spacing[row].y) -
                                   elementHeight / 2;
                            xPos -= containerWidth / 2;
                            break;
                    }

                    childRect.anchoredPosition = new Vector2(xPos, yPos) + Offset;
                    childRect.sizeDelta = new Vector2(elementWidth, elementHeight);

                    currentElement++;
                }
            }
        }


#if UNITY_EDITOR
        private void OnValidate()
        {
            if (rectTransform != null)
            {
                ArrangeElements();
            }
        }
#endif
    }

 

코드를 멋있게 커스터마이징해서 공유해주세요! 

더 많은 기능을 추가할 수 있다고 생각합니다.

 

감사합니다.