#nullable enable using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace UVC.UI.Tab { /// /// 탭 컨텐츠의 동적 로딩을 관리하는 클래스입니다. /// TabView에 소속되어 지연 로딩 기능을 제공합니다. /// public class TabContentLoader : MonoBehaviour { [Tooltip("지연 로딩 사용 여부")] [SerializeField] private bool lazyLoadTabs = true; [Tooltip("최대 동시 로드 탭 수")] [SerializeField] private int maxLoadedTabs = 3; [Tooltip("탭 전환 시 자동 로드/언로드 여부")] [SerializeField] private bool autoManageTabs = true; /// /// 지연 로딩할 탭 컨텐츠 정보를 정의하는 클래스입니다. /// [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 _lazyContents = new List(); // 초기화 여부 private bool _isInitialized = false; // 현재 활성화된 탭 ID private string? _currentTabID = null; // 부모 TabView 참조 private TabView? _parentTabView; // 이벤트 public UnityEvent OnTabContentLoaded = new UnityEvent(); public UnityEvent OnTabContentUnloaded = new UnityEvent(); private void Awake() { _parentTabView = GetComponentInParent(); } /// /// 탭 로더를 초기화합니다. /// public void InitializeTabLoader() { if (_isInitialized) return; if (!lazyLoadTabs) { PreloadAllTabs(); } _isInitialized = true; } /// /// 지연 로드 탭 설정을 추가합니다. /// public bool AddLazyTabContent(string tabID, string prefabPath, object? initialData = null) { LazyTabContent content = new LazyTabContent(tabID, prefabPath, initialData); _lazyContents.Add(content); return true; } /// /// 모든 지연 로드 설정을 제거합니다. /// public void ClearLazyContents() { foreach (var content in _lazyContents) { if (content.isLoaded && content.instance != null) { Destroy(content.instance); } } _lazyContents.Clear(); _isInitialized = false; } /// /// 특정 탭의 컨텐츠를 로드합니다. /// 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(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; } } /// /// 특정 탭 컨텐츠의 데이터를 업데이트합니다. /// private void UpdateContentData(LazyTabContent content) { if (content.instance != null && content.contentData != null) { ITabContent? tabContent = content.instance.GetComponent(); tabContent?.SetContentData(content.contentData); } } /// /// 특정 탭의 컨텐츠를 언로드합니다. /// 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; } } /// /// 현재 활성화된 탭을 제외한 모든 탭을 언로드합니다. /// public void UnloadAllExceptCurrent(string currentTabID) { foreach (var content in _lazyContents) { if (content.tabID != currentTabID && content.isLoaded) { UnloadTabContent(content.tabID); } } } /// /// 모든 탭 컨텐츠를 미리 로드합니다. /// public void PreloadAllTabs() { foreach (var content in _lazyContents) { if (!content.isLoaded) { LoadTabContent(content.tabID); } } } /// /// 특정 탭의 데이터를 설정합니다. /// 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); } } } /// /// 특정 탭이 로드되었는지 확인합니다. /// public bool IsTabLoaded(string tabID) { LazyTabContent? content = _lazyContents.Find(c => c.tabID == tabID); return content?.isLoaded == true && content.instance != null; } /// /// 특정 탭의 컨텐츠 인스턴스를 가져옵니다. /// 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); } } } } }