using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace UVC.UI.Toolbar.View { /// /// 툴바 내의 라디오 버튼 그룹(UnityEngine.UI.ToggleGroup)을 생성하고 관리하는 헬퍼 클래스입니다. /// ToolbarView로부터 ToggleGroup 관련 로직을 위임받아 처리함으로써 ToolbarView의 복잡도를 낮추고 역할을 분리합니다. /// /// /// 주요 역할: /// - ToggleGroup 동적 생성: 라디오 버튼 모델의 GroupName을 기반으로 해당하는 ToggleGroup을 찾거나 새로 생성합니다. /// - 리소스 관리: 생성된 ToggleGroup GameObject들을 내부적으로 관리하며, 툴바가 정리될 때 함께 파괴하여 메모리 누수를 방지합니다. /// - 레이아웃 독립성: 생성된 ToggleGroup GameObject가 툴바의 UI 레이아웃에 영향을 주지 않도록 LayoutElement 컴포넌트를 추가하고 `ignoreLayout`을 true로 설정합니다. /// /// /// /// // 이 클래스는 ToolbarView 내부에서 다음과 같이 사용됩니다. /// /// // 1. ToolbarView의 Awake 메서드에서 ToggleGroupManager 인스턴스 생성 /// // public class ToolbarView : MonoBehaviour /// // { /// // public Transform toolbarContainer; /// // private ToggleGroupManager _toggleGroupManager; /// // /// // void Awake() /// // { /// // _toggleGroupManager = new ToggleGroupManager(toolbarContainer); /// // } /// // // ... /// // } /// /// // 2. 라디오 버튼(RadioButton)의 UI 프로세서에서 `GetOrCreateToggleGroup` 호출 /// // public class ToolbarRadioButtonViewProcessor : IButtonViewProcessor /// // { /// // public void SetupButtonInteractions(ToolbarButtonBase buttonModel, GameObject buttonUIObject, ToolbarView viewContext) /// // { /// // ToolbarRadioButton radioModel = buttonModel as ToolbarRadioButton; /// // Toggle uiToggle = buttonUIObject.GetComponent(); /// // if (uiToggle != null) /// // { /// // // viewContext의 GetOrCreateToggleGroup을 호출하면 내부적으로 ToggleGroupManager의 메서드가 실행됩니다. /// // uiToggle.group = viewContext.GetOrCreateToggleGroup(radioModel.GroupName); /// // } /// // } /// // } /// /// // 3. 툴바를 정리(Clear)할 때 Manager의 Clear 메서드 호출 /// // public class ToolbarView : MonoBehaviour /// // { /// // protected virtual void ClearToolbar() /// // { /// // // ... 다른 UI 요소 정리 ... /// // _toggleGroupManager.Clear(); // 생성된 모든 토글 그룹 GameObject들을 파괴 /// // } /// // } /// /// public class ToggleGroupManager { private readonly Transform _container; private readonly Dictionary _toggleGroups = new Dictionary(); /// /// ToggleGroupManager의 새 인스턴스를 초기화합니다. /// /// 생성될 ToggleGroup GameObject들이 자식으로 추가될 부모 Transform입니다. 보통 툴바의 컨테이너를 지정합니다. public ToggleGroupManager(Transform container) { _container = container; } /// /// 지정된 그룹 이름에 해당하는 UnityEngine.UI.ToggleGroup을 가져오거나, 없으면 새로 생성합니다. /// /// 찾거나 생성할 토글 그룹의 이름입니다. /// 요청된 이름에 해당하는 ToggleGroup 컴포넌트입니다. public ToggleGroup GetOrCreateToggleGroup(string groupName) { if (string.IsNullOrEmpty(groupName)) { Debug.LogError("ToggleGroupManager: GetOrCreateToggleGroup - groupName이 null이거나 비어있습니다."); // 그룹 이름이 없는 비정상적인 경우를 위해 임시 그룹을 생성하여 반환합니다. GameObject tempGroupObj = new GameObject($"ToggleGroup_UnnamedDynamic"); tempGroupObj.transform.SetParent(_container, false); return tempGroupObj.AddComponent(); } // 캐시된 딕셔너리에서 그룹 이름으로 ToggleGroup을 찾아봅니다. if (!_toggleGroups.TryGetValue(groupName, out ToggleGroup group)) { // 해당하는 ToggleGroup이 없으면 새로 생성합니다. GameObject groupObj = new GameObject($"ToggleGroup_{groupName}"); groupObj.transform.SetParent(_container); // RectTransform을 추가하고 크기를 0으로 설정하여 레이아웃에 영향을 주지 않도록 합니다. RectTransform groupRect = groupObj.AddComponent(); groupRect.sizeDelta = Vector2.zero; groupRect.anchoredPosition = Vector2.zero; groupRect.anchorMin = Vector2.zero; groupRect.anchorMax = Vector2.one; // ToggleGroup 컴포넌트를 추가합니다. group = groupObj.AddComponent(); group.allowSwitchOff = false; // 라디오 버튼 그룹은 일반적으로 항상 하나가 선택된 상태를 유지해야 하므로, 선택 해제를 허용하지 않습니다. // LayoutElement를 추가하고 ignoreLayout을 true로 설정하여 부모의 LayoutGroup 계산에서 이 GameObject를 무시하도록 합니다. LayoutElement element = groupObj.AddComponent(); element.ignoreLayout = true; // 새로 생성된 그룹을 딕셔너리에 추가하여 다음 요청 시 재사용할 수 있도록 합니다. _toggleGroups.Add(groupName, group); } return group; } /// /// 이 매니저를 통해 생성된 모든 ToggleGroup GameObject들을 파괴하고 내부 캐시를 비웁니다. /// 툴바가 다시 렌더링되거나 파괴될 때 호출하여 메모리 누수를 방지합니다. /// public void Clear() { if (_toggleGroups == null) return; foreach (var groupObj in _toggleGroups.Values) { if (groupObj != null && groupObj.gameObject != null) { // 생성했던 GameObject를 파괴합니다. Object.Destroy(groupObj.gameObject); } } _toggleGroups.Clear(); } } }