유니티 기본 UI외에 가장 많이 만들어서 사용하는 두번째 기능은 아마 누가 뭐라고 해도 Scroll-Snap 기능일 것이다.
게임의 페이지 전환이나 배너 넘기기, 인벤토리 넘기기등 모바일 게임 초창기부터 등장한 UI 기능으로 지금까지도 널리 , 그리고 적극적으로 사용되고 있는 Scroll-Snap은 더이상 직접 구현할 필요가 없어 졌다.
찾아보니 무료로 AssetStore에 올라와 있었기 때문이다.
따라서 코드를 전체를 올릴 수도 있겠지만 그건 도리가 아니고 주요한 필드멤버와 메소드만 추출해서 살펴보자.
public MovementAxis movementAxis = MovementAxis.Horizontal; // 가로/세로 지정
public bool automaticallyLayout = true; // 자식 패널의 사이즈를 제어한다.
public int startingPanel = 0; //시작할 패널을 선택한다.
public Button previousButton = null; // 앞패널로 이동하는 퍼튼
public Button nextButton = null; // 뒤 버튼
public GameObject pagination = null; // 현재 위치를 보여주는 아이콘
public SnapTarget snapTarget = SnapTarget.Next; //선택할 타겟의 종류를 바꿈.
주요 필드 멤버 들이다.
private void Setup()
{
if (NumberOfPanels == 0) return;
// ScrollRect
if (movementType == MovementType.Fixed)
{
scrollRect.horizontal = (movementAxis == MovementAxis.Horizontal);
scrollRect.vertical = (movementAxis == MovementAxis.Vertical);
}
else
{
scrollRect.horizontal = scrollRect.vertical = true;
} // 스크롤 방향을 필드 변수에 따라 설정한다
// Panels
size = (sizeControl == SizeControl.Manual) ? size : new Vector2(GetComponent<RectTransform>().rect.width, GetComponent<RectTransform>().rect.height);
Panels = new GameObject[NumberOfPanels];
PanelsRT = new RectTransform[NumberOfPanels];
for (int i = 0; i < NumberOfPanels; i++) // 자식 패널들을 사이즈 세팅하고 정리한다.
{
Panels[i] = Content.GetChild(i).gameObject;
PanelsRT[i] = Panels[i].GetComponent<RectTransform>();
if (movementType == MovementType.Fixed && automaticallyLayout)
{
PanelsRT[i].anchorMin = new Vector2(movementAxis == MovementAxis.Horizontal ? 0f : 0.5f, movementAxis == MovementAxis.Vertical ? 0f : 0.5f);
PanelsRT[i].anchorMax = new Vector2(movementAxis == MovementAxis.Horizontal ? 0f : 0.5f, movementAxis == MovementAxis.Vertical ? 0f : 0.5f);
float x = (rightMargin + leftMargin) / 2f - leftMargin;
float y = (topMargin + bottomMargin) / 2f - bottomMargin;
Vector2 marginOffset = new Vector2(x / size.x, y / size.y);
PanelsRT[i].pivot = new Vector2(0.5f, 0.5f) + marginOffset;
PanelsRT[i].sizeDelta = size - new Vector2(leftMargin + rightMargin, topMargin + bottomMargin);
float panelPosX = (movementAxis == MovementAxis.Horizontal) ? i * (automaticLayoutSpacing + 1f) * size.x + (size.x / 2f) : 0f;
float panelPosY = (movementAxis == MovementAxis.Vertical) ? i * (automaticLayoutSpacing + 1f) * size.y + (size.y / 2f) : 0f;
PanelsRT[i].anchoredPosition = new Vector2(panelPosX, panelPosY);
}
}
// Content
if (movementType == MovementType.Fixed)
{
// Automatic Layout
if (automaticallyLayout)
{
Content.anchorMin = new Vector2(movementAxis == MovementAxis.Horizontal ? 0f : 0.5f, movementAxis == MovementAxis.Vertical ? 0f : 0.5f);
Content.anchorMax = new Vector2(movementAxis == MovementAxis.Horizontal ? 0f : 0.5f, movementAxis == MovementAxis.Vertical ? 0f : 0.5f);
Content.pivot = new Vector2(movementAxis == MovementAxis.Horizontal ? 0f : 0.5f, movementAxis == MovementAxis.Vertical ? 0f : 0.5f);
Vector2 min = PanelsRT[0].anchoredPosition;
Vector2 max = PanelsRT[NumberOfPanels - 1].anchoredPosition;
float contentWidth = (movementAxis == MovementAxis.Horizontal) ? (NumberOfPanels * (automaticLayoutSpacing + 1f) * size.x) - (size.x * automaticLayoutSpacing) : size.x;
float contentHeight = (movementAxis == MovementAxis.Vertical) ? (NumberOfPanels * (automaticLayoutSpacing + 1f) * size.y) - (size.y * automaticLayoutSpacing) : size.y;
Content.sizeDelta = new Vector2(contentWidth, contentHeight);
}
// Infinite Scrolling
if (infinitelyScroll)
{
scrollRect.movementType = ScrollRect.MovementType.Unrestricted;
contentLength = (movementAxis == MovementAxis.Horizontal) ? (Content.rect.width + size.x * infiniteScrollingEndSpacing) : Content.rect.height + size.y * infiniteScrollingEndSpacing;
OnInfiniteScrolling(true);
}
// Occlusion Culling
if (useOcclusionCulling)
{
OnOcclusionCulling(true);
}
}
else
{
automaticallyLayout = infinitelyScroll = useOcclusionCulling = false;
}
// Starting Panel // 시작 패널을 세팅한다
float xOffset = (movementAxis == MovementAxis.Horizontal || movementType == MovementType.Free) ? Viewport.rect.width / 2f : 0f;
float yOffset = (movementAxis == MovementAxis.Vertical || movementType == MovementType.Free) ? Viewport.rect.height / 2f : 0f;
Vector2 offset = new Vector2(xOffset, yOffset);
previousContentAnchoredPosition = Content.anchoredPosition = -PanelsRT[startingPanel].anchoredPosition + offset;
CurrentPanel = TargetPanel = NearestPanel = startingPanel;
// Previous Button
if (previousButton != null)
{
previousButton.onClick.RemoveAllListeners();
previousButton.onClick.AddListener(GoToPreviousPanel);
}
// Next Button
if (nextButton != null)
{
nextButton.onClick.RemoveAllListeners();
nextButton.onClick.AddListener(GoToNextPanel);
}
// Pagination
if (pagination != null)
{
Toggles = pagination.GetComponentsInChildren<Toggle>();
for (int i = 0; i < Toggles.Length; i++)
{
if (Toggles[i] != null)
{
Toggles[i].isOn = (i == startingPanel);
Toggles[i].interactable = (i != TargetPanel);
int panelNum = i;
Toggles[i].onValueChanged.RemoveAllListeners();
Toggles[i].onValueChanged.AddListener(delegate
{
if (Toggles[panelNum].isOn && toggleNavigation)
{
GoToPanel(panelNum);
}
});
}
}
}
}
메인 세팅하는 메소드이다.
몇몇 세팅하는 부분만 잘 사용해도 Scroll_snap기능을 쉽게 사용할 수 있다.
쉽고 간단하게 스크롤 스냅을 써보자.
'스터디' 카테고리의 다른 글
[유니티 C# 테크닉] 대리자 한방정리 : 델리게이트, Action/Func, 이벤트, 델리게이트 체인 (0) | 2021.08.07 |
---|---|
유니티 C# 테크닉 - Async, Update, Coroutine (0) | 2021.07.28 |
유니티 확장 UI - Image.Type.Fill을 이용한 쿨타임 아이콘 (0) | 2021.07.17 |
유니티 확장 UI - 무한 스크롤 (0) | 2021.07.15 |
개발 기법 스터디 - 개발 방법론 (0) | 2021.07.08 |