434 lines
18 KiB
C#
434 lines
18 KiB
C#
namespace Gpm.Ui.Sample
|
|
{
|
|
using Gpm.Ui;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
/// <summary>
|
|
/// InfiniteScroll의 다양한 기능을 보여주는 예제 클래스입니다.
|
|
/// 데이터 추가, 삭제, 업데이트, 필터링, 특정 위치로 스크롤하는 방법을 구현합니다.
|
|
/// </summary>
|
|
public class InfiniteScrollSample : MonoBehaviour
|
|
{
|
|
// Unity 에디터의 인스펙터 창에서 연결할 UI 요소들입니다.
|
|
[Header("UI Components")]
|
|
[Tooltip("세로 방향으로 스크롤되는 InfiniteScroll 컴포넌트입니다.")]
|
|
public InfiniteScroll verticalScrollList = null;
|
|
|
|
[Tooltip("가로 방향으로 스크롤되는 InfiniteScroll 컴포넌트입니다.")]
|
|
public InfiniteScroll horizontalScrollList = null;
|
|
|
|
[Tooltip("동작 로그를 표시할 UI Text 컴포넌트입니다.")]
|
|
public Text logText = null;
|
|
|
|
[Tooltip("현재 데이터 개수를 표시할 UI Text 컴포넌트입니다.")]
|
|
public Text dataCount = null;
|
|
|
|
[Tooltip("로그 텍스트를 담고 있는 ScrollRect입니다. 로그가 길어질 경우 스크롤을 위함입니다.")]
|
|
public ScrollRect logScrollRect = null;
|
|
|
|
[Tooltip("특정 데이터로 이동할 때 사용할 Dropdown UI입니다.")]
|
|
public Dropdown moveDataSelect = null;
|
|
|
|
[Tooltip("스크롤 이동 애니메이션 타입을 선택할 Dropdown UI입니다.")]
|
|
public Dropdown moveDataTypeSelect = null;
|
|
|
|
[Tooltip("스크롤 이동 시간을 입력할 InputField UI입니다.")]
|
|
public InputField moveDataTime = null;
|
|
|
|
[Tooltip("특정 아이템 인덱스로 이동할 때 사용할 InputField UI입니다.")]
|
|
public InputField moveItemSelect = null;
|
|
|
|
[Tooltip("현재 생성된 아이템(UI 오브젝트)의 개수를 표시할 Text 컴포넌트입니다.")]
|
|
public Text itemCount = null;
|
|
|
|
// 내부 상태 관리를 위한 변수들입니다.
|
|
|
|
/// <summary>
|
|
/// 새로 추가되는 데이터에 고유한 인덱스를 부여하기 위한 카운터입니다.
|
|
/// </summary>
|
|
private int index = 0;
|
|
|
|
/// <summary>
|
|
/// 총 몇 개의 데이터가 삽입되었는지 추적하는 카운터입니다.
|
|
/// </summary>
|
|
private int insertCount = 0;
|
|
|
|
/// <summary>
|
|
/// 총 몇 개의 데이터가 제거되었는지 추적하는 카운터입니다.
|
|
/// </summary>
|
|
private int removeCount = 0;
|
|
|
|
/// <summary>
|
|
/// 스크롤 뷰에 표시될 모든 데이터를 관리하는 리스트입니다.
|
|
/// InfiniteScroll은 이 리스트의 데이터를 기반으로 UI 아이템을 생성하고 재활용합니다.
|
|
/// </summary>
|
|
private List<TestItemData> dataList = new List<TestItemData>();
|
|
|
|
/// <summary>
|
|
/// 화면에 로그를 표시하기 위한 StringBuilder입니다.
|
|
/// 문자열을 반복적으로 합칠 때 성능상 이점을 가집니다.
|
|
/// </summary>
|
|
private StringBuilder log = new StringBuilder();
|
|
|
|
/// <summary>
|
|
/// 스크립트가 처음 활성화될 때 호출되는 Unity 생명주기 메서드입니다.
|
|
/// 주로 이벤트 리스너를 등록하고 초기화 작업을 수행합니다.
|
|
/// </summary>
|
|
private void Start()
|
|
{
|
|
// 세로 스크롤 리스트에서 아이템이 선택되었을 때 호출될 콜백 함수를 등록합니다.
|
|
// 사용자가 아이템을 클릭하면 해당 아이템의 데이터 정보가 로그에 표시됩니다.
|
|
verticalScrollList.AddSelectCallback((data) =>
|
|
{
|
|
// 콜백으로 받은 데이터(data)는 InfiniteScrollData 타입이므로,
|
|
// 실제 데이터 타입인 TestItemData로 형변환하여 사용합니다.
|
|
AddLog(string.Format("vertical select data : {0}", ((TestItemData)data).index.ToString()));
|
|
});
|
|
|
|
// 가로 스크롤 리스트에 대한 선택 콜백도 동일하게 등록합니다.
|
|
horizontalScrollList.AddSelectCallback((data) =>
|
|
{
|
|
AddLog(string.Format("horizontal select data : {0}", ((TestItemData)data).index.ToString()));
|
|
});
|
|
|
|
// 'MoveToData' 드롭다운의 값이 변경될 때 호출될 리스너를 등록합니다.
|
|
// 선택된 옵션의 인덱스를 기반으로 해당 데이터 위치로 스크롤을 이동시킵니다.
|
|
moveDataSelect.onValueChanged.AddListener((option) =>
|
|
{
|
|
MoveToDataIndex(option);
|
|
});
|
|
|
|
// 'MoveToItem' 입력 필드의 값이 변경될 때 호출될 리스너를 등록합니다.
|
|
// 입력된 아이템 인덱스로 스크롤을 이동시킵니다.
|
|
moveItemSelect.onValueChanged.AddListener((text) =>
|
|
{
|
|
int index = 0;
|
|
if (int.TryParse(text, out index) == false)
|
|
{
|
|
AddLog("Time is not Number");
|
|
}
|
|
|
|
MoveToItemIndex(index);
|
|
});
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 스크롤 뷰가 마지막 데이터 위치에 도달했는지 확인하고 결과를 로그에 출력합니다.
|
|
/// InfiniteScroll.IsMoveToLastData() API의 사용 예시입니다.
|
|
/// </summary>
|
|
public void IsMoveToLastData()
|
|
{
|
|
AddLog(string.Format("Is move to last data vertical:{0},horizontal:{1}",
|
|
verticalScrollList.IsMoveToLastData().ToString(), horizontalScrollList.IsMoveToLastData().ToString()));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 새로운 데이터를 생성하여 스크롤 리스트의 끝에 추가합니다.
|
|
/// InfiniteScroll.InsertData() API의 사용 예시입니다.
|
|
/// </summary>
|
|
public void InsertData()
|
|
{
|
|
// 1. 새로운 데이터 객체를 생성하고 고유 인덱스를 할당합니다.
|
|
TestItemData data = new TestItemData();
|
|
data.index = index++;
|
|
|
|
// 2. 내부 데이터 리스트(dataList)에 추가하여 데이터를 관리합니다.
|
|
dataList.Add(data);
|
|
|
|
// 3. InfiniteScroll 컴포넌트에 데이터를 삽입하여 UI에 반영합니다.
|
|
// 이 호출로 인해 스크롤 뷰는 새로운 아이템을 표시할 준비를 합니다.
|
|
verticalScrollList.InsertData(data);
|
|
horizontalScrollList.InsertData(data);
|
|
|
|
// 4. 'MoveToData' 드롭다운에도 해당 데이터 인덱스를 옵션으로 추가합니다.
|
|
var options = new List<Dropdown.OptionData>() { new Dropdown.OptionData(data.index.ToString()) };
|
|
moveDataSelect.AddOptions(options);
|
|
|
|
// 5. 카운터를 업데이트하고 로그를 남깁니다.
|
|
++insertCount;
|
|
UpdateDataCount();
|
|
|
|
AddLog(string.Format("Insert Data : {0}", index - 1));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 스크롤 리스트의 모든 데이터를 제거합니다.
|
|
/// InfiniteScroll.Clear() API의 사용 예시입니다.
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
// 1. InfiniteScroll의 모든 데이터를 제거합니다.
|
|
// 이 메서드는 내부 데이터 목록과 화면의 UI 아이템을 모두 정리합니다.
|
|
verticalScrollList.Clear();
|
|
horizontalScrollList.Clear();
|
|
|
|
// 2. 이 예제에서 사용하는 내부 데이터 리스트와 UI 요소도 함께 정리합니다.
|
|
removeCount += dataList.Count;
|
|
dataList.Clear();
|
|
|
|
moveDataSelect.ClearOptions();
|
|
|
|
// 3. 카운터를 업데이트하고 로그를 남깁니다.
|
|
UpdateDataCount();
|
|
|
|
AddLog("Clear Data");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 데이터 리스트에서 무작위로 하나의 데이터를 선택하여 제거합니다.
|
|
/// InfiniteScroll.RemoveData() API의 사용 예시입니다.
|
|
/// </summary>
|
|
public void Remove()
|
|
{
|
|
if (dataList.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 1. 무작위로 데이터 인덱스를 선택합니다.
|
|
int dataIndex = GetDataIndexByRandom();
|
|
TestItemData data = dataList[dataIndex];
|
|
|
|
// 2. InfiniteScroll에서 해당 데이터를 제거합니다.
|
|
// 스크롤 뷰는 이 데이터를 표시하던 UI 아이템을 숨기거나 재활용합니다.
|
|
verticalScrollList.RemoveData(data);
|
|
horizontalScrollList.RemoveData(data);
|
|
|
|
// 3. 내부 데이터 리스트와 UI 드롭다운에서도 해당 데이터를 제거합니다.
|
|
dataList.Remove(data);
|
|
|
|
int optionIndex = moveDataSelect.options.FindIndex(p => p.text.Equals(data.index.ToString()));
|
|
if (optionIndex != -1)
|
|
{
|
|
moveDataSelect.options.RemoveAt(optionIndex); // 드롭다운 표시값 갱신
|
|
}
|
|
|
|
// 4. 카운터를 업데이트하고 로그를 남깁니다.
|
|
removeCount++;
|
|
UpdateDataCount();
|
|
|
|
AddLog(string.Format("RemoveChild data : {0}", data.index));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 무작위로 하나의 데이터를 선택하여 내용을 업데이트합니다.
|
|
/// InfiniteScroll.UpdateData() API의 사용 예시입니다.
|
|
/// </summary>
|
|
public void UpdateData()
|
|
{
|
|
if (dataList.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 1. 무작위로 업데이트할 데이터를 선택합니다.
|
|
int dataIndex = GetDataIndexByRandom();
|
|
TestItemData data = dataList[dataIndex];
|
|
|
|
// 2. 데이터의 내용을 변경합니다. (예: 설명 텍스트 업데이트)
|
|
data.description = string.Format("Updated : {0}", DateTime.Now.ToString("T"));
|
|
|
|
// 3. InfiniteScroll에 데이터가 변경되었음을 알립니다.
|
|
// 이 호출을 받은 스크롤 뷰는 해당 데이터를 표시하는 UI 아이템을 찾아 내용을 새로고침합니다.
|
|
verticalScrollList.UpdateData(data);
|
|
horizontalScrollList.UpdateData(data);
|
|
|
|
AddLog(string.Format("Update data : {0}", data.index));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 스크롤 리스트의 모든 데이터를 업데이트합니다.
|
|
/// InfiniteScroll.UpdateAllData() API의 사용 예시입니다.
|
|
/// </summary>
|
|
public void UpdateAllData()
|
|
{
|
|
// 1. 내부 데이터 리스트의 모든 항목을 순회하며 내용을 변경합니다.
|
|
for (int index = 0; index < dataList.Count; ++index)
|
|
{
|
|
dataList[index].description = string.Format("Updated : {0}", DateTime.Now.ToString("T"));
|
|
}
|
|
|
|
// 2. InfiniteScroll에 모든 데이터가 변경되었음을 알립니다.
|
|
// 스크롤 뷰는 현재 화면에 보이는 모든 아이템을 새로고침합니다.
|
|
verticalScrollList.UpdateAllData();
|
|
horizontalScrollList.UpdateAllData();
|
|
|
|
AddLog("Update all data");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 데이터 및 아이템 개수를 UI에 최신 정보로 업데이트합니다.
|
|
/// </summary>
|
|
private void UpdateDataCount()
|
|
{
|
|
// dataList.Count는 원본 데이터의 총 개수입니다.
|
|
dataCount.text = string.Format("Data Count : {0} (insert[{1}] remove[{2}])", dataList.Count, insertCount, removeCount);
|
|
|
|
// InfiniteScroll.GetItemCount()는 필터링이 적용된 후, 실제 화면에 표시될 아이템의 개수입니다.
|
|
itemCount.text = verticalScrollList.GetItemCount().ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 스크롤을 가장 처음 위치로 이동시킵니다.
|
|
/// </summary>
|
|
public void MoveToFirstData()
|
|
{
|
|
verticalScrollList.MoveToFirstData();
|
|
horizontalScrollList.MoveToFirstData();
|
|
|
|
AddLog("Move to first data");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 스크롤을 가장 마지막 위치로 이동시킵니다.
|
|
/// </summary>
|
|
public void MoveToLastData()
|
|
{
|
|
verticalScrollList.MoveToLastData();
|
|
horizontalScrollList.MoveToLastData();
|
|
|
|
AddLog("Move to last data");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 지정된 '아이템 인덱스'로 스크롤을 이동시킵니다.
|
|
/// '아이템 인덱스'는 필터링과 정렬이 적용된 후 화면에 보이는 순서입니다.
|
|
/// </summary>
|
|
/// <param name="itemIndex">이동할 대상의 아이템 인덱스</param>
|
|
private void MoveToItemIndex(int itemIndex)
|
|
{
|
|
float time = 0;
|
|
if (float.TryParse(moveDataTime.text, out time) == false)
|
|
{
|
|
AddLog("Time is not Number");
|
|
}
|
|
|
|
// MoveTo API를 사용하여 (아이템 인덱스, 이동 타입, 이동 시간)을 인자로 전달합니다.
|
|
verticalScrollList.MoveTo(itemIndex, (InfiniteScroll.MoveToType)moveDataTypeSelect.value, time);
|
|
horizontalScrollList.MoveTo(itemIndex, (InfiniteScroll.MoveToType)moveDataTypeSelect.value, time);
|
|
|
|
AddLog(string.Format("Move to ItemIndex : {0}", itemIndex));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 지정된 '데이터 인덱스'로 스크롤을 이동시킵니다.
|
|
/// '데이터 인덱스'는 원본 데이터 리스트(dataList)에서의 순서입니다.
|
|
/// </summary>
|
|
/// <param name="dataIndex">이동할 대상의 데이터 인덱스</param>
|
|
private void MoveToDataIndex(int dataIndex)
|
|
{
|
|
float time = 0;
|
|
if (float.TryParse(moveDataTime.text, out time) == false)
|
|
{
|
|
AddLog("Time is not Number");
|
|
}
|
|
|
|
// MoveToFromDataIndex 또는 MoveTo(data) API를 사용할 수 있습니다.
|
|
// 여기서는 두 가지 방법을 무작위로 선택하여 보여줍니다.
|
|
if (UnityEngine.Random.Range(0, 2) == 0)
|
|
{
|
|
// 방법 1: 데이터 인덱스를 직접 사용
|
|
verticalScrollList.MoveToFromDataIndex(dataIndex, (InfiniteScroll.MoveToType)moveDataTypeSelect.value, time);
|
|
horizontalScrollList.MoveToFromDataIndex(dataIndex, (InfiniteScroll.MoveToType)moveDataTypeSelect.value, time);
|
|
}
|
|
else
|
|
{
|
|
// 방법 2: 데이터 객체를 직접 사용
|
|
TestItemData data = dataList[dataIndex];
|
|
|
|
verticalScrollList.MoveTo(data, (InfiniteScroll.MoveToType)moveDataTypeSelect.value, time);
|
|
horizontalScrollList.MoveTo(data, (InfiniteScroll.MoveToType)moveDataTypeSelect.value, time);
|
|
}
|
|
|
|
AddLog(string.Format("Move to DataIndex : {0}", dataIndex));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 홀수 인덱스를 가진 데이터만 표시하도록 필터를 설정합니다.
|
|
/// InfiniteScroll.SetFilter() API의 사용 예시입니다.
|
|
/// </summary>
|
|
public void FilterOdd()
|
|
{
|
|
// Predicate<InfiniteScrollData>는 데이터를 받아 bool을 반환하는 함수입니다.
|
|
// true를 반환하는 데이터만 화면에 표시됩니다.
|
|
Predicate<InfiniteScrollData> func = (data) =>
|
|
{
|
|
if (data is TestItemData testData)
|
|
{
|
|
// 인덱스가 짝수인 데이터만 남깁니다 (홀수번째 아이템).
|
|
return (testData.index % 2) == 0;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
// 생성한 필터 함수를 스크롤 뷰에 설정합니다.
|
|
verticalScrollList.SetFilter(func);
|
|
horizontalScrollList.SetFilter(func);
|
|
|
|
UpdateDataCount();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 짝수 인덱스를 가진 데이터만 표시하도록 필터를 설정합니다.
|
|
/// </summary>
|
|
public void FilterEven()
|
|
{
|
|
Predicate<InfiniteScrollData> func = (data) =>
|
|
{
|
|
if (data is TestItemData testData)
|
|
{
|
|
// 인덱스가 홀수인 데이터만 남깁니다 (짝수번째 아이템).
|
|
return (testData.index % 2) == 1;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
verticalScrollList.SetFilter(func);
|
|
horizontalScrollList.SetFilter(func);
|
|
|
|
UpdateDataCount();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 모든 필터를 제거하고 모든 데이터를 표시합니다.
|
|
/// </summary>
|
|
public void FilterAll()
|
|
{
|
|
// SetFilter에 null을 전달하면 필터가 해제됩니다.
|
|
verticalScrollList.SetFilter(null);
|
|
horizontalScrollList.SetFilter(null);
|
|
|
|
UpdateDataCount();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 화면의 로그 UI에 새로운 텍스트를 추가하고, 로그 창을 맨 아래로 스크롤합니다.
|
|
/// </summary>
|
|
/// <param name="text">로그에 추가할 문자열</param>
|
|
private void AddLog(string text)
|
|
{
|
|
log.AppendLine(text);
|
|
logText.text = log.ToString();
|
|
|
|
// 로그가 추가될 때마다 스크롤을 맨 아래로 내려 최신 로그를 보여줍니다.
|
|
// verticalNormalizedPosition = 0.0f가 맨 아래를 의미합니다.
|
|
logScrollRect.verticalNormalizedPosition = 0.0f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 데이터 리스트에서 유효한 랜덤 인덱스를 반환합니다.
|
|
/// </summary>
|
|
/// <returns>0과 (dataList.Count - 1) 사이의 랜덤 정수</returns>
|
|
private int GetDataIndexByRandom()
|
|
{
|
|
return UnityEngine.Random.Range(0, dataList.Count);
|
|
}
|
|
}
|
|
} |