다음의 영상을 참고하여 궁수의 전설 UI를 제작하고 있다.
지난 번 글까지는 각 패널의 세로 스크롤 뷰를 구현했었다.
이번 시간에는 밑의 탭 버튼을 구현해보자.
하단 탭버튼 만들기
이제 아래쪽의 탭버튼을 만들 차례이다.
가장 상위 Canvas 바로 하위에 Image를 하나 생성해주고 이름은 Tab으로 하자.
PosY
= -875, Width
= 1080, Height
= 180으로 세팅해주자.
그 뒤 Source Image를 1편에서 만들어놨던
R_4
스프라이트로 해주자.
패널 넘어다니는 버튼 만들기
그 후 Tab 하위에 Button을 만들어주자.
버튼 하위의 Text 오브젝트는 지워주고,
Source Image
는 R_5로 해주자.
이를 네 번 복제해서 총 다섯개를 만들어주자.
그 후 위치를 맞춰주기 위해
Tab에다가 Horizontal Layout Group
을 추가해주자.
버튼들이 약간 이상하게 배치되어 있는 것을 볼 수 있다.
Horizontal Layout Group
에서
Control Child Size
의 Width
와 Height
를
한 번씩 체크했다가 해제해주면 원래 모습으로 잘 정렬이 된다.
이제 첫 번째 버튼의 Width
를 360으로,
나머지 버튼들의 Width
는 180으로 조정해주자.
이제 각 버튼들의 Inspector에서
OnClick()
에 요소를 새로 추가하고,
Scroll View
를 가져다 넣어주자.
이제 함수를 만들어줄 것이다.
NestedScrollManager.cs에 다음과 같은 함수를 추가하자.
public void TabClick(int n)
{
targetPos = pos[n];
}
이제 Inspector에서 연결만 해주면 끝이다.
마지막 버튼까지 쓰고 싶다면
NestedScrollManager에서 SIZE = 5
로 바꿔주고
패널을 다섯개로 만들어주자.
버튼 사이즈 조정하기
이제 내가 지금 있는 패널의 버튼을 다른 버튼보다 두 배 커지도록 만들어 줄 것이다.
이름은 TabSlider로 해주고, Hierarchy에서 자식들 중 가장 상단에 위치하도록 위치를 옮겨주자.
Slider는 다른 버튼들보다 뒤에 있어야하기 때문이다.
또한 Slider 역시 크기를 가지고 있기 때문에 버튼 배치가 뭉개지는데 이를 위해 추가적인 설정을 해주자.
Layout Element
에 Ignore Layout을 체크하게 되면
Horizontal Layout Group에 포함이 되지 않게 된다.
이제 TabSlider의 크기와 위치를
Pos X
= 270, PosY
= -90, Width
= 720, Height
= 180으로 맞춰준 뒤
자식 중 Background와 Fill Area는 지워주도록 하자.
우리는 Slider의 Handle Slide Area
만 사용할 것이기 때문이다.
그 후 여백이 없게
Handle Slide Area
의 Rect Transform의 상하좌우를 모두 0으로 만들자.
Handle Slide Area 하위에 있는 Handle의 경우
PosX
를 180, Width
를 360으로 설정하고,
Source Image를 R_6
으로 바꿔주자.
우리는 이 슬라이더를 직접 조작할 것이 아니기 때문에
Slider 컴포넌트의 Interactable
을 꺼주도록 하자.
그러면 색이 약간 희꾸무레하게 바뀌는데
Transition의 Color Tint
를 None
으로 바꿔주면 원래대로 돌아온다.
이제 다시 코드를 작성하자.
NestedScrollManager.cs에 다음 파트를 추가해주자.
[SerializeField] Slider tabSlider;
void Update()
{
tabSlider.value = scrollbar.value;
if (!isDrag) scrollbar.value = Mathf.Lerp(scrollbar.value, targetPos, 0.1f);
}
tabSlider를 연결해주고 확인해보면, 패널이 바뀔 때마다 Slider가 따라오는 것을 확인할 수 있다!
이제 어느 패널에 있는지에 따라 버튼들의 크기를 조정해주자.
NestedScrollManager.cs에 다음 파트를 추가하고 Inspector에서 Btn들을 지정해주자.
[SerializeField] RectTransform[] BtnRect;
이제 이 버튼들을 각각 접근해서 목표 버튼이라면 크기를 키워주고 그렇지 않다면은 원래 크기로 만들어 줄 것이다.
코드를 작성해주자.
몇 번 패널에 있는지를 알기 위해 targetIndex를 추가해줄 것이다.
NestedScrollManager.cs
int targetIndex; // 목표 인덱스 : targetPos가 바뀔 때 같이 바뀜
float SetPos()
{
for (int i = 0; i < SIZE; ++i)
if (scrollbar.value < pos[i] + distance * 0.5f && scrollbar.value > pos[i] - distance * 0.5)
{ // 절반거리를 기준으로 가까운 위치를 반환
targetIndex = i;
return pos[i];
}
return 0f;
}
public void OnEndDrag(PointerEventData eventData)
{
isDrag = false;
targetPos = SetPos();
// 스크롤뷰 드래그를 멈추면 한 패널만 보이도록 targetPos를 설정
if (curPos == targetPos)
{
if (eventData.delta.x > thresholdSpeed && curPos - distance >= 0)
{
--targetIndex;
targetPos = curPos - distance;
}
else if (eventData.delta.x < -thresholdSpeed && curPos + distance < 1f)
{
++targetIndex;
targetPos = curPos + distance;
}
}
// 목표가 수직스크롤이고, 옆에서 옮겨왔다면 수직스크롤을 맨 위로 올림
for (int i = 0; i < SIZE; ++i)
if (curPos != pos[i] && targetPos == pos[i])
{
Transform child = contentTr.GetChild(i);
if (child.GetComponent<ScrollScript>() != null)
child.GetChild(1).GetComponent<Scrollbar>().value = 1;
break;
}
}
void Update()
{
tabSlider.value = scrollbar.value;
if (!isDrag)
{
scrollbar.value = Mathf.Lerp(scrollbar.value, targetPos, 0.1f);
// 목표 버튼은 크기가 커짐
for (int i = 0; i < SIZE; ++i) BtnRect[i].sizeDelta = new Vector2(i == targetIndex ? 360 : 180, BtnRect[i].sizeDelta.y);
}
}
public void TabClick(int n)
{
targetIndex = n;
targetPos = pos[n];
}
Rect Transform
의 sizeDelta
가 무엇일지 궁금해 할 사람들이 있을텐데,
Rect Transform
의 Width
와 Height
를 Vector2
형태로 접근할 수 있는 속성이다.
탭버튼에 이미지 추가하기
이미지를 만들어서 꾸며줘보자.
Tab 오브젝트 하위에 Image를 생성하고
역시 Horizontal Layout Group
에 영향을 받지 않아야 하기 때문에
Layout Element
를 추가시켜 Ignore Layout
을 체크해주자.
Rect Transform은
Pos X
= 180, Pos Y
= -84.65, Width
= 180, Height
= 180으로 설정하자.
Source Image는 R_8
또는 자신이 원하는 것을 넣어주자.
이제 Image의 자식으로 Text를 추가시켜주고, 아래에 배치한 뒤 글자를 써주자.
다 꾸미면 이렇게 된다.
이제 텍스트들은 전부 비활성화 해주자.
NestedScrollManager에서
RectTransform
의 배열로 BtnImageRect
를 선언해주고,
Inspector에서 각 이미지들을 연결해주자.
[SerializeField] RectTransform[] BtnImageRect;
또 NestedScrollManager.cs의 Update를 끝부분에 다음과 같은 코드를 추가하여주자.
void Update()
{
tabSlider.value = scrollbar.value;
if (!isDrag)
{
scrollbar.value = Mathf.Lerp(scrollbar.value, targetPos, 0.1f);
// 목표 버튼은 크기가 커짐
for (int i = 0; i < SIZE; ++i) BtnRect[i].sizeDelta = new Vector2(i == targetIndex ? 360 : 180, BtnRect[i].sizeDelta.y);
}
if (Time.time < 0.1f) return;
for (int i = 0; i < SIZE; ++i)
{
Vector3 BtnTargetPos = BtnRect[i].anchoredPosition3D;
BtnImageRect[i].anchoredPosition3D = Vector3.Lerp(BtnImageRect[i].anchoredPosition3D, BtnTargetPos, 0.25f);
}
}
여기서 Rect Transform
의 anchoredPosition3D
는
해당 Rect Transform
의 Position
을 Vector3 형태로 받아오는 프로퍼티이다.
시간이 0.1f 이하일 때 함수를 종료해주는 이유는 처음에는 순간적으로 다른 이미지들의 위치가 0이기 때문이다.
실행시켜보면 슬라이드 시킬 때는 문제없이 아이콘들이 이동하는데 클릭하면 화면이동이 일어나지 않는 것을 알 수 있다.
이것은 이미지가 버튼들을 가리고 있어서 그런건데,
Image
컴포넌트의 Raycast Target
이라는 성분을 끄면 해결된다.
이제 우리는 활성화된 탭의 이미지가 위로 살짝 올라오면서, 크기가 커지고, 텍스트가 활성화되도록 만들어주고 싶다.
NestedScrollManager.cs의 Update를 다음과 같이 수정해주자.
void Update()
{
tabSlider.value = scrollbar.value;
if (!isDrag)
{
scrollbar.value = Mathf.Lerp(scrollbar.value, targetPos, 0.1f);
// 목표 버튼은 크기가 커짐
for (int i = 0; i < SIZE; ++i) BtnRect[i].sizeDelta = new Vector2(i == targetIndex ? 360 : 180, BtnRect[i].sizeDelta.y);
}
if (Time.time < 0.1f) return;
for (int i = 0; i < SIZE; ++i)
{
Vector3 BtnTargetPos = BtnRect[i].anchoredPosition3D;
Vector3 BtnTargetScale = Vector3.one;
bool textActive = false;
if (i == targetIndex)
{
BtnTargetPos.y = -23f;
BtnTargetScale = new Vector3(1.2f, 1.2f, 1);
textActive = true;
}
BtnImageRect[i].anchoredPosition3D = Vector3.Lerp(BtnImageRect[i].anchoredPosition3D, BtnTargetPos, 0.25f);
BtnImageRect[i].localScale = Vector3.Lerp(BtnImageRect[i].localScale, BtnTargetScale, 0.25f);
BtnImageRect[i].transform.GetChild(0).gameObject.SetActive(textActive);
}
}
이제 완성이다!
이제 각 패널에다가 표시할 컨텐츠를 만들어주기만 하면 되는 것이다.
이렇게 디테일을 하나하나 살려주는 것이 직접 만져봤을 때 느낌이 너무 좋은 것 같다.
여러분도 시간이 난다면 꼭 따라해서 만들어보도록 하자.
Uploaded by N2T
'개발 > Unity 내일배움캠프 TIL' 카테고리의 다른 글
Unity 3D 타일맵 만들기 (0) | 2023.09.25 |
---|---|
Unity 어트리뷰트 (Attribute) (0) | 2023.09.22 |
Unity2D 궁수의 전설 UI 따라만들기 (2) (0) | 2023.09.20 |
Unity2D 궁수의 전설 UI 따라만들기 (1) (0) | 2023.09.19 |
사원수, 쿼터니언 (Quaternion) (1) | 2023.09.18 |