| | |
| | | using System.Linq; |
| | | using DG.Tweening; |
| | | using Cysharp.Threading.Tasks; |
| | | using UnityEngine.EventSystems; |
| | | |
| | | /// <summary> |
| | | /// UI管理器 - 负责管理所有UI界面的显示、隐藏和层级 |
| | |
| | | Debug.LogError("无法找到UI根节点"); |
| | | return; |
| | | } |
| | | GameObject.DontDestroyOnLoad(root); |
| | | } |
| | | |
| | | // 无论是从场景找到还是新实例化的,都确保跨场景不被销毁 |
| | | GameObject.DontDestroyOnLoad(root); |
| | | |
| | | uiRoot = root.transform; |
| | | uiRoot.position = Vector3.zero; |
| | |
| | | layerTransformCache.Add(UILayer.Mid, midTrans); |
| | | layerTransformCache.Add(UILayer.System, systemTrans); |
| | | layerTransformCache.Add(UILayer.Loading, loadingTrans); |
| | | |
| | | LogUIRootEventSystemState("InitUIRoot"); |
| | | } |
| | | |
| | | public Transform GetUIRoot() |
| | |
| | | Debug.LogError("无法加载UI根节点"); |
| | | return; |
| | | } |
| | | GameObject.DontDestroyOnLoad(root); |
| | | } |
| | | |
| | | // 无论是从场景找到还是新实例化的,都确保跨场景不被销毁 |
| | | GameObject.DontDestroyOnLoad(root); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | } |
| | | } |
| | | |
| | | public void DumpUIDiagnostics(string context) |
| | | { |
| | | var eventSystem = EventSystem.current; |
| | | Debug.Log($"[UIManager][Diag] {context} EventSystem={(eventSystem != null ? eventSystem.name : "<null>")} selected={(eventSystem != null && eventSystem.currentSelectedGameObject != null ? eventSystem.currentSelectedGameObject.name : "<null>")} loadingIndicatorActive={(_loadingIndicatorGO != null && _loadingIndicatorGO.activeSelf)} loadingRefCount={_loadingRefCount} uiStackCount={uiStack.Count}"); |
| | | LogUIRootEventSystemState(context); |
| | | |
| | | var uiArray = new UIBase[uiStack.Count]; |
| | | uiStack.CopyTo(uiArray, 0); |
| | | foreach (var ui in uiArray) |
| | | { |
| | | if (ui == null) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | var uiCanvas = ui.GetComponent<Canvas>(); |
| | | var uiCanvasGroup = ui.GetComponent<CanvasGroup>(); |
| | | Debug.Log($"[UIManager][Diag] {context} ui={ui.GetType().Name} active={ui.gameObject.activeInHierarchy} layer={ui.uiLayer} sortingOrder={(uiCanvas != null ? uiCanvas.sortingOrder : -1)} siblingIndex={ui.transform.GetSiblingIndex()} canvasGroup.blocksRaycasts={(uiCanvasGroup != null ? uiCanvasGroup.blocksRaycasts : false)} canvasGroup.interactable={(uiCanvasGroup != null ? uiCanvasGroup.interactable : false)}"); |
| | | } |
| | | } |
| | | |
| | | private void LogUIRootEventSystemState(string context) |
| | | { |
| | | if (uiRoot == null) |
| | | { |
| | | Debug.Log($"[UIManager][Diag] {context} uiRoot=<null>"); |
| | | return; |
| | | } |
| | | |
| | | var eventSystemTransform = uiRoot.Find("EventSystem"); |
| | | if (eventSystemTransform == null) |
| | | { |
| | | Debug.Log($"[UIManager][Diag] {context} uiRoot.EventSystem child=<null>"); |
| | | return; |
| | | } |
| | | |
| | | var eventSystemComponent = eventSystemTransform.GetComponent<EventSystem>(); |
| | | var standaloneInputModule = eventSystemTransform.GetComponent<StandaloneInputModule>(); |
| | | var baseInputModule = eventSystemTransform.GetComponent<BaseInputModule>(); |
| | | Debug.Log($"[UIManager][Diag] {context} uiRoot.EventSystem childExists=true activeSelf={eventSystemTransform.gameObject.activeSelf} activeInHierarchy={eventSystemTransform.gameObject.activeInHierarchy} eventSystemComponent={(eventSystemComponent != null)} standaloneInputModule={(standaloneInputModule != null)} baseInputModuleType={(baseInputModule != null ? baseInputModule.GetType().Name : "<null>")} currentMatchesChild={(EventSystem.current == eventSystemComponent)}"); |
| | | } |
| | | |
| | | private void EnsureLoadingIndicator() |
| | | { |
| | | if (_loadingIndicatorGO != null) return; |
| | |
| | | // 遍历UI栈,设置排序顺序 |
| | | UIBase[] uiArray = new UIBase[uiStack.Count]; |
| | | uiStack.CopyTo(uiArray, 0); |
| | | |
| | | // WebGL/IL2CPP 下被 Destroy 的对象访问任何属性都会 NullReferenceException, |
| | | // 必须在使用前过滤掉(Unity 伪 null:C# 引用非 null 但 == null 为 true) |
| | | uiArray = System.Array.FindAll(uiArray, ui => ui != null); |
| | | |
| | | // 先按照UILayer进行排序,然后再按照栈顺序排序 |
| | | Dictionary<UIBase, int> uiOrderDict = new Dictionary<UIBase, int>(); |
| | |
| | | |
| | | Array.Sort(uiArray, (a, b) => |
| | | { |
| | | if (a == null || b == null) return 0; |
| | | int layerCompare = a.uiLayer.CompareTo(b.uiLayer); |
| | | if (layerCompare != 0) |
| | | return layerCompare; |
| | |
| | | // 遍历排序后的UI数组,设置排序顺序 |
| | | foreach (var ui in uiArray) |
| | | { |
| | | if (ui == null) continue; |
| | | // 获取基础排序顺序 |
| | | int baseSortingOrder = GetBaseSortingOrderForLayer(ui.uiLayer); |
| | | // 计算当前UI的排序顺序 |