본문 바로가기

[Unity] 넷플릭스 같은 멀티 스크롤뷰 UI 만들기

앤디가이 2022. 6. 13.

Unity UI에서 스크롤 뷰를 확장하여 넷플릭스(Netflix) UI 같이 멀티 스크롤 뷰가 되는 방법에 대해 알아보자.

 

Unity UI 제작 시 메인 페이지는 상하 좌우로 스크롤이 되어야 하고, 메인 페이지 내 서브 페이지는 좌우로 스크롤돼야 하는 화면을 만든다고 가정해보자. (넷플릭스 메인화면과 같은 화면)

기본적으로 메인 페이지의 ScrollRect 컴포넌트의 Horizontal 옵션을 체크 해제하여 상하 좌우 스크롤만 되도록 하게 하고, 서브 페이지의 ScrollRect에는 Vertical 옵션을 체크 해제하여 좌우만 스크롤되도록 구성을 하는 것이 일반적이다.

이럴 경우 문제가 서브페이지에서 상하 스크롤을 할 경우 상하 스크롤이 되지 않는다. 서브 페이지에서 상하 스크롤을 할 경우, 메인 페이지가 상하로 움직이길 원하지만, 기능적으로 구현이 안되어 있다.

 

문제 화면은 아래 영상을 참고해보자. 

검은색 부분이 상하 스크롤되어야 하는 메인화면 영역이고, 푸른색 영역이 좌우 스크롤돼야 하는 서브화면 영역이라고 생각하면 된다.

Unity 기본 ScrollView 문제화면

즉, 멀티로 스크롤 뷰를 구성할 경우, 상하 이동은 상위 페이지를 스크롤하고, 좌우 스크롤은 서브 페이지를 스크롤하게 만들어 줘야 한다. 
반대의 경우도 마찬가지다.(메인 페이지를 좌우 스크롤로 구성하고, 서브 페이지를 상하 스크롤로 구현할 경우)

 

위와 같은 멀티 스크롤 시 문제점을 보완하기 위해 ScrollRect의 확장 클래스를 제작해 보자.

 

1. UIMultiScrollRect Class 작성

 - 해당 클래스는 ScrollRect를 상속받은 확장 클래스이다.

 - OnBeginDrag 및 OnDrag 유니티 이벤트 함수를 바탕으로 사용자가 상하 스크롤 중인지, 좌우 스크롤 중인지를 파악하여 부모를 스크롤해야 하는지를 판단한다.

 - Math.Abs()의 절댓값 함수를 활용하여 eventData.delta의 x, y값 이동 수치 값을 통해 좌우, 상하 스크롤인지 판단한다.

 - Scripts 폴더를 만든 후 UIMultiScrollRectClass.cs 클래스를 만든 후 아래와 같이 작성한다.

using UnityEngine;
using UnityEngine.UI;
using System;
using UnityEngine.EventSystems;

/// <summary>
/// Multi ScrollRect
/// </summary>
public class UIMultiScrollRect : ScrollRect
{

    private bool routeToParent = false;

    private void DoForParents<T>(Action<T> action) where T : IEventSystemHandler
    {
        Transform parent = transform.parent;
        while (parent != null)
        {
            foreach (var component in parent.GetComponents<Component>())
            {
                if (component is T)
                    action((T)(IEventSystemHandler)component);
            }
            parent = parent.parent;
        }
    }


    public override void OnInitializePotentialDrag(PointerEventData eventData)
    {
        DoForParents<IInitializePotentialDragHandler>((parent) => { parent.OnInitializePotentialDrag(eventData); });
        base.OnInitializePotentialDrag(eventData);
    }

    public override void OnDrag(UnityEngine.EventSystems.PointerEventData eventData)
    {
        if (routeToParent)
            DoForParents<IDragHandler>((parent) => { parent.OnDrag(eventData); });
        else
            base.OnDrag(eventData);
    }


    public override void OnBeginDrag(UnityEngine.EventSystems.PointerEventData eventData)
    {
        if (!horizontal && Math.Abs(eventData.delta.x) > Math.Abs(eventData.delta.y))
            routeToParent = true;
        else if (!vertical && Math.Abs(eventData.delta.x) < Math.Abs(eventData.delta.y))
            routeToParent = true;
        else
            routeToParent = false;

        if (routeToParent)
            DoForParents<IBeginDragHandler>((parent) => { parent.OnBeginDrag(eventData); });
        else
            base.OnBeginDrag(eventData);
    }


    public override void OnEndDrag(UnityEngine.EventSystems.PointerEventData eventData)
    {
        if (routeToParent)
            DoForParents<IEndDragHandler>((parent) => { parent.OnEndDrag(eventData); });
        else
            base.OnEndDrag(eventData);
        routeToParent = false;
    }
}

 

2. ScrollRect -> UIMultiScrollRect 컴포넌트로 교체

 - ScrollRect가 붙어있는 오브젝트에 ScrollRect를 제거하고 UIMultiScrollRect 컴포넌트로 교체해준다.

 - Content, Viewport, Scrollbar 항목에 오브젝트를 연결해준다.

 - 메인(상하 스크롤) 화면의 컴포넌트 구성은 아래와 같다.

Main MultiScrollRect 설정
Main MultiScrollRect 설정

 - 서브(좌우 스크롤) 화면의 컴포넌트 구성은 아래와 같다.

Sub MultiScrollRect 설정
Sub MultiScrollRect 설정

 

3. 결과 화면

 - 서브 페이지에서 상하 스크롤을 시도할 경우 상위 스크롤 객체인 Main-ScrollView가 스크롤되는 것을 볼 수 있다.

 - 서브 페이지에서 좌우 스크롤을 시도할 경우 해당 서브 페이지만 좌우 스크롤되는 것을 볼 수 있다.

 

멀티 스크롤뷰 적용 완료 화면

댓글