안녕하세요 주인장입니다.
오늘은 Unity 재사용 스크롤 리스트에 대해서 다뤄보겠습니다.
ScrollView를 사용할 때 리스트 아이템이 많아지면,
하나씩 Instantiate해서 보여주는 방식은 금방 프레임 드랍과 메모리 낭비로 이어집니다.
이를 해결하기 위해 아이템을 재활용하는 방식을 사용하면,
적은 오브젝트로도 수천 개의 데이터를 효율적으로 표시할 수 있습니다.
이번 글에서는 개념 설명보다는
실제 코드와 결과를 중심으로,
재사용 스크롤 리스트가 어떻게 동작하는지를 간단히 확인해보겠습니다.
1. 변수선언
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RecycleScrollView : MonoBehavior
{
private ScrollRect _scroll;
public RankingItem itemPrefab;
public float itemHeight;
public float offSet = 10f;
public List<int> dataList;
private List<RankingItem> itemList;
}
변수설명
- _scroll → 사용할 ScrollView에 붙은 ScrollRect 컴포넌트입니다.
- itemPrefab → 재사용 리스트에 들어갈 슬롯 프리팹입니다.
- itemHeight → 슬롯 프리팹의 세로 높이 값입니다.
- offset → 슬롯 간의 간격입니다, 임의로 10f로 지정했습니다.
- dataList → 동적으로 생성할 데이터 리스트입니다.
실제 프로젝트에서는 보통 API 응답(Json)을 역직렬화한 데이터를 사용합니다. - itemList → 재사용 스크롤 리스트에 사용될 슬롯 객체들의 리스트입니다.
2. 핵심 기능 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RecycleScrollView : MonoBehaviour
{
private ScrollRect _scroll;
public RankingItem itemPrefab;
public float itemHeight;
public float offSet = 10f;
public List<int> dataList;
private List<RankingItem> itemList;
/// <summary>
/// ScrollRect 컴포넌트 초기화 및 아이템 높이 계산
/// </summary>
void Awake()
{
_scroll = GetComponent<ScrollRect>();
itemHeight = itemPrefab.GetComponent<RectTransform>().rect.height;
Debug.Log($"##### itemHeight : {itemHeight}");
Debug.Log($"##### scrollRect.rect.height / (itemHeight + offSet) : {_scroll.GetComponent<RectTransform>().rect.height / (itemHeight + offSet)}");
}
/// <summary>
/// 더미 데이터 생성 및 초기 아이템 세팅
/// </summary>
private void Start()
{
dataList.Clear();
for (int i = 0; i < 10000; i++)
{
dataList.Add(i);
}
CreateItem();
SetContentHeight();
}
/// <summary>
/// 스크롤 시 아이템 재배치 및 데이터 갱신
/// </summary>
private void Update()
{
foreach (RankingItem item in itemList)
{
bool isChanged = RelocationItem(item);
if (isChanged)
{
int index = (int)(-item.transform.localPosition.y / (itemHeight + offSet));
SetData(item, index);
}
}
}
/// <summary>
/// 화면에 표시할 아이템 풀 생성
/// </summary>
private void CreateItem()
{
RectTransform scrollRect = _scroll.GetComponent<RectTransform>();
itemList = new List<RankingItem>();
int itemCount;
if (dataList.Count <= scrollRect.rect.height / (itemHeight + offSet))
{
itemCount = dataList.Count;
}
else
{
itemCount = (int)(scrollRect.rect.height / (itemHeight + offSet) + 2);
}
for (int i = 0; i < itemCount; i++)
{
RankingItem item = Instantiate<RankingItem>(itemPrefab, _scroll.content);
itemList.Add(item);
item.transform.localPosition = new Vector3(0, -itemHeight * 0.5f - i * (itemHeight + offSet));
SetData(item, i);
}
}
/// <summary>
/// ScrollView 콘텐츠 영역의 전체 높이 설정
/// </summary>
private void SetContentHeight()
{
_scroll.content.sizeDelta = new Vector2(_scroll.content.sizeDelta.x, dataList.Count * (itemHeight + offSet) - offSet);
}
/// <summary>
/// 화면 밖으로 벗어난 아이템을 위/아래로 재배치하여 재사용
/// </summary>
private bool RelocationItem(RankingItem item)
{
RectTransform scrollRect = _scroll.GetComponent<RectTransform>();
float scrollHeight = scrollRect.rect.height;
float contentY = _scroll.content.anchoredPosition.y;
if (item.transform.localPosition.y + contentY > itemHeight + offSet)
{
item.transform.localPosition -= new Vector3(0, itemList.Count * (itemHeight + offSet) * 2f);
RelocationItem(item);
return true;
}
else if (item.transform.localPosition.y + contentY < -scrollHeight - (itemHeight + offSet))
{
item.transform.localPosition += new Vector3(0, itemList.Count * (itemHeight + offSet));
RelocationItem(item);
return true;
}
else return false;
}
/// <summary>
/// 아이템에 표시할 데이터 세팅
/// </summary>
private void SetData(RankingItem item, int index)
{
if (index < 0 || index >= dataList.Count)
{
item.gameObject.SetActive(false);
return;
}
item.gameObject.SetActive(true);
item.RankNumber.text = $"{index}";
item.UserName.text = $"테스트 닉네임 {index}";
}
}
3. 데이터 스크립트 (용도에 따라 커스터마이징 필요)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RankingItem : MonoBehaviour
{
public Text RankNumber;
public Text UserName;
}
4. 결과
오늘의 기록은 여기까지. 주인장은 이만 로그아웃 합니다. 모두 평안한 밤 보내세요!
'개발 > Unity' 카테고리의 다른 글
| [Unity] 클라이언트에서 사용할 수 있는 안티치트 기법 (1) (0) | 2025.11.03 |
|---|---|
| [Unity] 유니티에서 다른 앱 호출 방법 (0) | 2025.10.27 |
| [Unity] 스트링 파싱 (0) | 2025.10.22 |
| [Unity] IOS 빌드 (0) | 2025.10.17 |
| [에셋/툴] Skybox Blender (0) | 2025.10.16 |