본문 바로가기

유니티

[UI Tool Kit] 04 . 레이아웃과 트랜지션 애니메이션

[ UI 오버레이 ]

[ Bottom Sheet ]

버튼을 눌러 화면 하단에서 UI가 올라오는 것을 Bottom Sheet / Action Sheet이라고 한다 .

특징은 기존 UI를 건들지 않고 오버레이 함이 특징이다 .

 

 

[ 부모 추가 ]

기존 UI의 부모가 될 Visual Element를 추가한다 .

문제는 Size를 100%로 함에도 화면을 덮지 못하고 기존 UI를 밀어올린다 .

 

[ 포지션 : Relative / Absolute ]

[ 상황 재현 ]

다음과 같은 상황에서 파란 UI는 중앙에 그려져야 한다 . 이렇게 배치됨은 flex의 설정 때문이다 ..

 

UGUI의 LayoutGroup에 추가된것과 같은 상황인데 , 이떄 Layout Element의 Ignore Layout과 같은 설정이 필요하다 .

Postion , Absolute(레이아웃의 영향 받지 않음 )를 선택하면 같은 효과를 받을 수 있다.

이를 사용하면 Layout의 영향을 받지 않는다 . cf ) Relative(레이아웃의 영향을 받음)

 

[ Flex : Shrink / Grow ]

[ Shrink 상황 재현 ]

해당 상황에서 레이아웃이 올라가고 , 파란 레이아웃 역시 원래 설정한 500/500사이즈와 다르게 적용 되어 있다 .

이는 Flex - Shrink값 때문이다 . ( 1이 기본으로 들어 있기 때문)

레이아웃에 영향을 미치는 다른 Visual Element들이 Shrink값 총합에서 차지하는 크기만큼 더 많이 줄어든다 .

 

[ Grow ]

grow 역시 같다 . 빈 공간을 매울지 결정한다 .

이는 웹의 반응형 레이아웃에 알맞다 .

 

[ 바텀 시트 ]

[ 부모 조작 ]

다시 돌아와 부모의 position을 Absolute로 한다 . 이 상황에서 Flex -Grow는 사용이 불가하다 .

 

[ 가림막 생성 ]

부모가 Absolute를 사용해 자식은 Relative사용이 가능하다 . Grow를 1로 만든다 .

불투명한 검정으로 만든다 .

 

[ Bottom Sheet 생성 ]

가림막을 형제로 가지는 바텀 시트를 만든다 . Position은 Absolute로 정한다 . 

버튼 / 두개의 라벨 / 사진이 필요하다 .

 

[ Lanbel 조작 ]

해당 라벨은 스타일 시트로 만들어 보자 .

Inlined styles는 UXML의 재사용성과 성능상의 이유로  Style sheet의 사용을 권장한다 . 각 레이블에 적용한다 .

 

[ 버튼 생성 ]

부모의 우측에 설정 . Absolute로 우측 상단에 넣어준다 .

결과물

스크립트를 통해 버튼을 누르면 애니메이션이 재생되며 바텀 시트가 올라온다 .

지금은 특정 UI 내부에 바텀시트가 들어있지만 재사용성 / 관리 / 성능 을 위해 별도의 UXML파일을 불러온다 .

[ 디스플레이 : Flex , Node ]

[ Opacity 동작 ]

버튼을 누르면 바텀 그룹이 사라지고 나타난다 .

사라짐은 Display의 Opacity를 조작한다 (UGUI 의 Canvas Group의 알파값 동작과 같음)

Opacity 값은 자식에게 상속된다 .

 

[ 문제 ]

사실 보이지만 않을 뿐 , 아래의 다른 UI와의 상호작용 (hover)등을 막고 있다 . 

지금 필요한건 보이지 않고 ,입력도 막지 않는 상태가 필요하다 .

 

[ Display ]

이를 위해 Display 속성을 활용하자 . 눈 모양 아이콘을 비활성화 하면 보이지 않고 입력도 잘 처리한다 .

디스플레이를 끄면 레이아웃 그룹도 변함을 볼 수 있다 .

 

[ 스크립트 준비 ]

[ 스크립트 생성 ]

C#스크립트를 생성 , UI Controller로 생성하고 UI Document 가 붙은 오브젝트에 연결한다 .

특정 UI를 찾기 위해서 사용하는 UQuery 는 UI 계층구조 최상위 노드가 필요하다 .

 

UI Builder 의 Hirearchy는 Visual Tree라고도 칭한다.

Hirearchy에는 보이지 않는 Root Visual Element가 존재한다 .

 

각 요소를 스크립트에서 찾는것까지의 과정은 다음과 같다 .

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//선언으로 UI ToolKit의 기능 사용
using UnityEngine.UIElements;

public class UIController : MonoBehaviour
{
    //바텀시트 그룹 전체를 담는다
    private VisualElement _bottomController;
    //열기 버튼
    private Button _openButton;
    //닫기 버튼
    private Button _closeButton;


    // Start is called before the first frame update
    void Start()
    {
        //UI상 특정 Elements를 찾을떄 사용하는 UQuery . 이를 위해 UI 계층구조 최상위 루트 노드가 필요하다 .
        var root = GetComponent<UIDocument>().rootVisualElement;

        //UQuery는 루트.Q<타입>("이름");
        //바텀 컨트롤러
        _bottomController = root.Q<VisualElement>("Container_Botton");
        //버튼들
        _openButton = root.Q<Button>("Button_Open");
        _closeButton = root.Q<Button>("Button_Close");

        //시작시 바텀그룹을 감춘다 - 그룹의 display에 접근하여 꺼준다.
        _bottomController.style.display = DisplayStyle.None;


    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

[ 스크립트 : 버튼 ]

[ 버튼 콜백 등록 ]

에디터상 버튼의 콜백함수는 버튼의 OnClick에 추가 가능했다 . UI ToolKit에서는 스크립트로만 가능하다 .

        //버튼 . RegisterCallback<이벤트 타입>(할일) 의 방식으로 등록
        _openButton.RegisterCallback<ClickEvent>(OnOpenButtonClicked);
        _closeButton.RegisterCallback<ClickEvent>(OnCloseButtonClicked);


    private void OnOpenButtonClicked(ClickEvent evt)
    {
        //바텀 시트 그룹을 보여준다
        _bottomController.style.display = DisplayStyle.Flex;
    }

    private void OnCloseButtonClicked(ClickEvent evt)
    {
        //바텀 시트 그룹을 보여준다
        _bottomController.style.display = DisplayStyle.None;
    }

 

[ USS 트랜지션 애니메이션 ]

 

버튼을 눌러 바텀 시트가 위로 올라오고 가림막이 서서히 어두워지는 효과를 만든다 .

[ 바텀 시트 위치 조정 ]

Position의 Bottom 값을 바꿀 수 도 있지만 Transform 의 Translate의 값의 변경 할 수 있다 .

Position의 상하좌우와 Transform의 상하좌우는 뭐가 다를까?

유니티는 정적 레이아웃은 Position의 상하좌우를 사용하고 ,

애니메이션의 동적 값은 Layout재계산에 포함되지 않는 Transform을 권장한다 .

Transform - Translate - y에 100%를 넣어준다 . (자신의 높이만큼 이동)

 

[ 바텀 시트 이동 애니메이션 생성 ]

그전 버튼의 상태별 Transition 애니메이션은 Pseudo로 버튼의 스타일이 바뀔때 변화 전, 후를 애니메이션을 부드럽게

연결하였다 . 버튼은 Pseudo로 변화가 가능하지만 일반 Visual Element는 스크립트 제어가 필요하다 .

화면 안 / 밖 상태의 스타일 클래스를 만들어 주자 .

 

먼저 기본 상태에 애니메이션을 설정해준다 .

 

 위로 올라온 시트 / 내려온 시트 두가지의 스타일 클래스를 만들어 준다 .

 

Botto, Sheet Up을 지우자 따로 씬의 실행 없이 스타일에 변화에 따른 transitoin 애니메이션을 볼 수 있다 .(추가 역시 같음)

이를 스크립트로 구현해보자 .

 

[ 가림막 투명도 조절 ]

가림막의 Opacity를 0,1 상태의 스타일을 추출해서 만들어주자 .

 

[ 스크립트 - 스타일 ]

[ 적용 ]

    private void OnCloseButtonClicked(ClickEvent evt)
    {
        //바텀 시트 그룹을 보여준다
        _bottomController.style.display = DisplayStyle.None;

        //셀렉터를 끌어 비주얼 엘리먼트에 떨구는 것과 같다 .
        _bottomSheet.AddToClassList("bottomsheet--up");
        _scrim.AddToClassList("scrim--fadein");

    }
    
    
    private void OnOpenButtonClicked(ClickEvent evt)
    {
        //바텀 시트 그룹을 보여준다
        _bottomController.style.display = DisplayStyle.Flex;
        //이미 스타일이 있다면 변화 애니메이션이 안나오기에 초기화 필요 클래스 리스트에서 제거한다 .
        _bottomSheet.RemoveFromClassList("bottomsheet--up");
        _scrim.RemoveFromClassList("scrim--fadein");

    }

[ 스크린 값 변경을 CSS에서 수행 ]

css 파일 해당 스타일에서 값을 수정하자 . 다만 , 다음의 주의점이 존재한다 .

 

[ 아쉬운점 ]

창을 닫을때 바텀 시트 그룹 감춤이 우선되어 사라지는 애니메이션 적용이 이루어 지지 않는다 .

이는 다음 장에서 해결해보자 .