Files
EnglewoodLAB/Assets/Scripts/UVC/UI/Tab/TabContentLoader.cs

286 lines
9.1 KiB
C#

#nullable enable
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace UVC.UI.Tab
{
/// <summary>
/// 탭 컨텐츠의 동적 로딩을 관리하는 클래스입니다.
/// TabView에 소속되어 지연 로딩 기능을 제공합니다.
/// </summary>
public class TabContentLoader : MonoBehaviour
{
[Tooltip("지연 로딩 사용 여부")]
[SerializeField] private bool lazyLoadTabs = true;
[Tooltip("최대 동시 로드 탭 수")]
[SerializeField] private int maxLoadedTabs = 3;
[Tooltip("탭 전환 시 자동 로드/언로드 여부")]
[SerializeField] private bool autoManageTabs = true;
/// <summary>
/// 지연 로딩할 탭 컨텐츠 정보를 정의하는 클래스입니다.
/// </summary>
[System.Serializable]
public class LazyTabContent
{
public string tabID = "";
public string contentPrefabPath = "";
public bool isLoaded = false;
[HideInInspector] public GameObject? instance = null;
[HideInInspector] public object? contentData = null;
public LazyTabContent(string id, string path, object? data = null)
{
tabID = id;
contentPrefabPath = path;
contentData = data;
isLoaded = false;
instance = null;
}
}
// 지연 로드 컨텐츠 목록
private List<LazyTabContent> _lazyContents = new List<LazyTabContent>();
// 초기화 여부
private bool _isInitialized = false;
// 현재 활성화된 탭 ID
private string? _currentTabID = null;
// 부모 TabView 참조
private TabView? _parentTabView;
// 이벤트
public UnityEvent<string> OnTabContentLoaded = new UnityEvent<string>();
public UnityEvent<string> OnTabContentUnloaded = new UnityEvent<string>();
private void Awake()
{
_parentTabView = GetComponentInParent<TabView>();
}
/// <summary>
/// 탭 로더를 초기화합니다.
/// </summary>
public void InitializeTabLoader()
{
if (_isInitialized) return;
if (!lazyLoadTabs)
{
PreloadAllTabs();
}
_isInitialized = true;
}
/// <summary>
/// 지연 로드 탭 설정을 추가합니다.
/// </summary>
public bool AddLazyTabContent(string tabID, string prefabPath, object? initialData = null)
{
LazyTabContent content = new LazyTabContent(tabID, prefabPath, initialData);
_lazyContents.Add(content);
return true;
}
/// <summary>
/// 모든 지연 로드 설정을 제거합니다.
/// </summary>
public void ClearLazyContents()
{
foreach (var content in _lazyContents)
{
if (content.isLoaded && content.instance != null)
{
Destroy(content.instance);
}
}
_lazyContents.Clear();
_isInitialized = false;
}
/// <summary>
/// 특정 탭의 컨텐츠를 로드합니다.
/// </summary>
public GameObject? LoadTabContent(string tabID, object? data = null)
{
LazyTabContent? contentToLoad = _lazyContents.Find(c => c.tabID == tabID);
if (contentToLoad == null)
{
Debug.LogWarning($"지연 로드할 탭 컨텐츠를 찾을 수 없음: {tabID}");
return null;
}
// 이미 로드된 경우
if (contentToLoad.isLoaded && contentToLoad.instance != null)
{
if (data != null)
{
contentToLoad.contentData = data;
UpdateContentData(contentToLoad);
}
return contentToLoad.instance;
}
try
{
// 프리팹 로드
GameObject prefab = Resources.Load<GameObject>(contentToLoad.contentPrefabPath);
if (prefab == null)
{
Debug.LogError($"탭 컨텐츠 프리팹을 찾을 수 없음: {contentToLoad.contentPrefabPath}");
return null;
}
// TabView의 ContentContainer를 부모로 사용
Transform parentTransform = _parentTabView?.ContentContainer ?? transform;
// 인스턴스 생성
contentToLoad.instance = Instantiate(prefab, parentTransform);
contentToLoad.instance.name = $"LazyTabContent_{tabID}";
contentToLoad.instance.SetActive(false);
contentToLoad.isLoaded = true;
// 데이터 설정
if (data != null)
{
contentToLoad.contentData = data;
}
UpdateContentData(contentToLoad);
// 이벤트 발생
OnTabContentLoaded.Invoke(tabID);
Debug.Log($"지연 로드 탭 컨텐츠 로드됨: {tabID}");
return contentToLoad.instance;
}
catch (System.Exception ex)
{
Debug.LogError($"탭 컨텐츠 로드 중 오류 발생: {ex.Message}");
return null;
}
}
/// <summary>
/// 특정 탭 컨텐츠의 데이터를 업데이트합니다.
/// </summary>
private void UpdateContentData(LazyTabContent content)
{
if (content.instance != null && content.contentData != null)
{
ITabContent? tabContent = content.instance.GetComponent<ITabContent>();
tabContent?.SetContentData(content.contentData);
}
}
/// <summary>
/// 특정 탭의 컨텐츠를 언로드합니다.
/// </summary>
public bool UnloadTabContent(string tabID)
{
LazyTabContent? contentToUnload = _lazyContents.Find(c => c.tabID == tabID);
if (contentToUnload == null || !contentToUnload.isLoaded || contentToUnload.instance == null)
{
return false;
}
try
{
Destroy(contentToUnload.instance);
contentToUnload.instance = null;
contentToUnload.isLoaded = false;
OnTabContentUnloaded.Invoke(tabID);
Debug.Log($"지연 로드 탭 컨텐츠 언로드됨: {tabID}");
return true;
}
catch (System.Exception ex)
{
Debug.LogError($"탭 컨텐츠 언로드 중 오류 발생: {ex.Message}");
return false;
}
}
/// <summary>
/// 현재 활성화된 탭을 제외한 모든 탭을 언로드합니다.
/// </summary>
public void UnloadAllExceptCurrent(string currentTabID)
{
foreach (var content in _lazyContents)
{
if (content.tabID != currentTabID && content.isLoaded)
{
UnloadTabContent(content.tabID);
}
}
}
/// <summary>
/// 모든 탭 컨텐츠를 미리 로드합니다.
/// </summary>
public void PreloadAllTabs()
{
foreach (var content in _lazyContents)
{
if (!content.isLoaded)
{
LoadTabContent(content.tabID);
}
}
}
/// <summary>
/// 특정 탭의 데이터를 설정합니다.
/// </summary>
public void SetTabContentData(string tabID, object? data)
{
LazyTabContent? content = _lazyContents.Find(c => c.tabID == tabID);
if (content != null)
{
content.contentData = data;
if (content.isLoaded && content.instance != null)
{
UpdateContentData(content);
}
}
}
/// <summary>
/// 특정 탭이 로드되었는지 확인합니다.
/// </summary>
public bool IsTabLoaded(string tabID)
{
LazyTabContent? content = _lazyContents.Find(c => c.tabID == tabID);
return content?.isLoaded == true && content.instance != null;
}
/// <summary>
/// 특정 탭의 컨텐츠 인스턴스를 가져옵니다.
/// </summary>
public GameObject? GetTabInstance(string tabID)
{
LazyTabContent? content = _lazyContents.Find(c => c.tabID == tabID);
return content?.isLoaded == true ? content.instance : null;
}
private void OnDestroy()
{
foreach (var content in _lazyContents)
{
if (content.isLoaded && content.instance != null)
{
Destroy(content.instance);
}
}
}
}
}