스크롤 목록은 창문 뒤에서 긴 종이를 움직이는 것이다
Esc

    스크롤 목록은 창문 뒤에서 긴 종이를 움직이는 것이다

    –UnityUIuGUI

    인벤토리 화면을 떠올려 봅니다. 아이템 칸이 격자로 놓여 있고, 위아래로 밀면 목록이 움직이고, 창 밖으로 나간 칸은 보이지 않습니다.

    Unity 에서 이 화면은 부품 셋 으로 나뉩니다.

    1. 칸 Grid Layout Group 아이템을 격자로 늘어놓습니다 2. 종이 Content 3. 창 Viewport + 마스크 끌면 종이가 움직임 흐린 칸은 마스크가 가린 부분
    칸을 긴 종이에 붙이고, 그 종이를 창 뒤에서 움직입니다. 창 밖은 가림막이 가립니다.

    시안에서는 한 장의 그림이지만, 칸이 몇 줄로 꺾이는지는 1 번이, 끝에서 튕기는지는 3 번이 정합니다. 하나씩 봅니다.

    칸: Grid Layout Group

    앞에서 본 Horizontal Layout Group 은 자식이 알려 준 크기를 썼습니다. Grid Layout Group 은 그 값을 보지 않습니다.

    Horizontal Layout Group 48 80 56 자식이 알려 준 크기대로
    아이템이 알려 준 크기 48, 80, 56 이 그대로 쓰입니다.
    Grid Layout Group 48 80 56 자식 크기와 상관없이 전부 Cell Size 64
    숫자는 아이템이 원래 알려 준 크기인데, 칸은 모두 64 입니다.

    모든 칸이 Cell Size 하나로 같아집니다. 인벤토리 칸, 스킬 슬롯, 스테이지 선택 버튼처럼 크기가 같은 것을 늘어놓을 때 씁니다.

    Grid Layout Group Padding8, 8, 8, 8 Cell SizeX64Y64 SpacingX8Y8 Start CornerUpper Left Start AxisHorizontal Child AlignmentUpper Left ConstraintFlexible 1 안쪽 여백 2 모든 칸의 크기. 자식 크기는 무시 3 칸 사이 간격 4 첫 칸이 놓이는 모서리 5 가로로 먼저 채울지, 세로로 먼저 6 칸 묶음 전체의 정렬 7 몇 칸에서 꺾을지
    Grid Layout Group 인스펙터를 옮겨 그렸습니다. 2 번과 7 번이 Horizontal Layout Group 과 가장 다른 곳입니다.

    Constraint 가 몇 칸에서 줄을 꺾을지 정합니다.

    • Flexible: 부모 너비에 들어가는 만큼 한 줄에 놓고 꺾습니다. 화면이 넓어지면 한 줄의 칸 수가 늘어납니다
    • Fixed Column Count: 너비와 상관없이 정한 칸 수에서 꺾습니다. 넓으면 옆이 남고, 좁으면 칸이 부모 밖으로 나갑니다
    • Fixed Row Count: 줄 수를 고정합니다. 옆으로 스크롤되는 목록에 씁니다

    부모 너비와 설정을 바꿔 가며 보면, 칸이 어느 순서로 채워지고 어디서 꺾이는지 보입니다.

    • Child Alignment 는 칸 하나가 아니라 칸 묶음 전체 를 옮깁니다. Flexible 에서 남는 폭이 한쪽에 몰려 보이면 가운데로 두면 됩니다
    • 한 줄의 칸 수를 시안과 똑같이 지켜야 하면 Fixed Column Count 입니다. Flexible 은 기기마다 칸 수가 달라집니다
    • Start Corner 와 Start Axis 는 채우는 순서를 바꿉니다. 칸 안 숫자가 하이어라키 순서라, 아이템을 정렬해 넣을 때 무엇이 첫 칸에 오는지가 여기서 정해집니다

    줄이 늘어나면 높이도 늘려야 한다

    위에서 좁게를 누르면 넘친 칸이 생깁니다. Grid 도 부모 크기는 바꾸지 않습니다.

    스크롤 목록의 종이는 아이템 수만큼 길어져야 하니, 그리드에 Content Size Fitter 를 붙이고 Vertical Fit 을 Preferred Size 로 둡니다. 그리드의 Preferred 높이는 “지금 너비에서 필요한 줄 수” 로 계산됩니다.

    Horizontal Fit 은 Unconstrained 로 둡니다. Flexible 그리드의 Preferred 너비는 아이템 수의 제곱근만큼의 칸 수라서, 아이템이 10개면 4칸 폭으로 줄어듭니다.

    종이와 창: Scroll View

    GameObject > UI > Scroll View 로 만들면 이런 구조가 생깁니다.

    Scroll View Scroll Rect Viewport RectMask2D 또는 Mask Content Grid Layout Group, Content Size Fitter 아이템 1 아이템 2 ... 피벗 위 앵커 위 stretch 창 아래로 자람
    Content 가 종이, Viewport 가 창입니다. Content 는 피벗이 위라서 아이템이 늘면 아래로만 자랍니다.
    • Scroll View 에 붙은 Scroll Rect 가 끌기와 튕기기를 맡습니다
    • Viewport 가 창입니다. 이 크기가 곧 보이는 범위이고, 마스크가 붙어 창 밖을 가립니다
    • Content 가 종이입니다. 앵커는 위쪽 가로 stretch, 피벗은 위입니다. 앞에서 본 대로 크기는 피벗을 중심으로 바뀌니, 아이템이 늘어도 윗부분은 제자리이고 아래로만 길어집니다

    처음 만들어진 Content 는 높이가 정해진 값이라, 위 절처럼 Content Size Fitter 로 아이템 수에 맞춰야 합니다.

    Scroll Rect ContentContent (Rect Transform) Horizontal Vertical Movement TypeElastic Elasticity0.1 Inertia Deceleration Rate0.135 Scroll Sensitivity1 ViewportViewport (Rect Transform) 1 움직일 종이 2 가로로도 움직일지 3 세로로 움직일지 4 끝에서 어떻게 할지 5 끝을 넘었다 돌아오는 시간 6 손을 뗀 뒤 미끄러질지 7 1초 뒤 남는 속도의 비율 8 마우스 휠, 트랙패드 감도 9 창. 보이는 범위
    Scroll Rect 인스펙터를 옮겨 그렸습니다. 2 번, 4 번, 6 번이 목록의 손맛을 정합니다.

    2 번 Horizontal 은 기본으로 켜져 있습니다. 세로 목록인데 켜 두면 옆으로도 조금씩 흔들리니 끕니다.

    4 번부터 7 번은 말로 설명하기보다 직접 끌어 보는 편이 빠릅니다.

    • Elastic: 끝에서 고무줄처럼 버팁니다. 당길수록 무거워져서 손가락만큼 따라오지 않고, 놓으면 돌아옵니다. Elasticity 가 작을수록 빨리 돌아옵니다
    • Clamped: 끝에서 딱 멈춥니다
    • Unrestricted: 끝이 없습니다. 목록보다는 큰 지도처럼 경계가 없는 화면에 씁니다
    • Inertia 를 켜면 손을 뗀 뒤에도 미끄러집니다. Deceleration Rate 0.135 는 1초 뒤 속도가 13.5 퍼센트 남는다는 뜻입니다. 0 에 가까울수록 금방 멈추고, 1 에 가까울수록 오래 미끄러집니다
    • 위에서 마스크를 끄면 창 밖의 종이가 그대로 보입니다. 다음 절의 가림막이 하는 일입니다

    가림막: Mask 와 RectMask2D

    창 밖을 가리는 컴포넌트는 둘입니다. 자르는 모양이 다릅니다.

    틀 (Image + Mask) 동그란 이미지 + 자식 (사각 초상화) 결과 흐린 부분은 잘려서 안 보임 틀 이미지의 모양대로 자릅니다. Show Mask Graphic 을 끄면 틀은 안 그리고 모양만 씁니다.
    동그라미, 둥근 모서리처럼 사각형이 아닌 모양으로 자를 때 씁니다.
    Softness 0 아이템 1아이템 2아이템 3아이템 4아이템 5아이템 6 아이템 1아이템 2아이템 3아이템 4아이템 5아이템 6 Softness Y 24 아이템 1아이템 2아이템 3아이템 4아이템 5아이템 6 아이템 1아이템 2아이템 3아이템 4아이템 5아이템 6 창 (Viewport) 가장자리가 칼로 자른 듯 위아래가 흐리게 사라진다
    사각형으로만 자릅니다. 대신 가장자리를 흐리게 할 수 있고 더 가볍습니다.

    Mask 는 붙은 오브젝트의 이미지 모양대로 자식을 자릅니다.

    • 동그란 초상화, 둥근 모서리 카드처럼 사각형이 아닌 모양 을 만들 수 있습니다
    • GPU 의 스텐실이라는 방식을 써서 가장자리가 딱딱합니다. 흐리게 할 수 없습니다
    • 마스크를 그리고 되돌리는 그리기가 추가되고, 마스크 안의 요소는 밖의 요소와 배칭이 갈립니다

    RectMask2D 는 RectTransform 사각형으로만 자릅니다.

    • 이미지가 필요 없습니다
    • Softness 로 가장자리를 흐리게, Padding 으로 자르는 사각형을 안쪽으로 줄일 수 있습니다
    • 추가 그리기가 없고, 창 밖으로 완전히 나간 요소는 아예 그리지 않습니다. 아이템이 많은 긴 목록에 유리합니다
    • 같은 평면에 있는 2D 요소만 제대로 자릅니다. 3D 로 기울인 요소에는 맞지 않습니다

    고르는 법은 간단합니다. 스크롤 창처럼 사각형이면 RectMask2D, 사각형이 아닌 모양이면 Mask 입니다. Mask 로 자르면서 가장자리까지 흐리게 하고 싶다면 기본 컴포넌트로는 안 되고, 부드러운 마스크를 만들어 주는 플러그인이 필요합니다.

    시안을 넘길 때 적어 주면 좋은 것

    적어 줄 것 무엇이 정해지나
    한 줄에 몇 칸인지, 화면이 넓어지면 칸 수가 늘어나는지 Constraint (Flexible 또는 Fixed Column Count)
    칸 크기와 간격, 칸 묶음이 어느 쪽에 붙는지 Cell Size, Spacing, Child Alignment
    아이템이 어느 모서리부터 어떤 순서로 채워지는지 Start Corner, Start Axis
    어느 방향으로 스크롤되는지 Scroll Rect 의 Horizontal, Vertical
    끝에서 튕기는지 멈추는지, 손을 떼면 얼마나 미끄러지는지 Movement Type, Elasticity, Inertia, Deceleration Rate
    창의 모양 과 가장자리를 흐리게 할지 RectMask2D 의 Softness, 또는 Mask

    미끄러지는 느낌은 글로 전하기 어렵습니다. 비슷한 느낌의 게임이나 앱을 예로 들어 주면 맞추기 쉽습니다.

    정리

    • 스크롤 목록은 칸(Grid Layout Group), 종이(Content), 창(Viewport) 에 가림막(마스크) 을 더한 것입니다
    • Grid Layout Group 은 자식 크기를 무시하고 모두 Cell Size 로 만듭니다. Constraint 가 몇 칸에서 꺾을지 정합니다
    • 그리드도 부모 크기는 안 바꿉니다. 종이 높이는 Content Size Fitter 의 Vertical Fit Preferred Size 로 늘립니다
    • Content 는 피벗이 위 라서 아래로 자랍니다. 세로 목록이면 Scroll Rect 의 Horizontal 을 끕니다
    • 끝에서의 동작은 Movement Type, 손을 뗀 뒤의 미끄러짐은 Inertia 와 Deceleration Rate 가 정합니다
    • 사각형 창은 RectMask2D, 다른 모양은 Mask 입니다. RectMask2D 는 가볍고 가장자리를 흐리게 할 수 있습니다