lcy
2025-11-06 09bc892c7283df8757a07b646d5af21ddaa263d1
Main/Manager/UIManager.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using DG.Tweening;
/// <summary>
/// UI管理器 - 负责管理所有UI界面的显示、隐藏和层级
@@ -25,12 +26,17 @@
    private Transform staticTrans;
    private Transform bottomTrans;
    private Transform midTrans;
    private Transform topTrans;
    private Transform systemTrans;
    private Transform loadingTrans;
    // UI字典,存储所有已加载的UI,键为UI名称,值为UI实例
    private Dictionary<string, List<UIBase>> uiDict = new Dictionary<string, List<UIBase>>();
#if UNITY_EDITOR
    public
#else
    private
#endif
    Dictionary<string, List<UIBase>> uiDict = new Dictionary<string, List<UIBase>>();
    // 存储关闭但未销毁的UI,键为UI名称,值为UI实例
    private Dictionary<string, List<UIBase>> closedUIDict = new Dictionary<string, List<UIBase>>();
@@ -44,7 +50,7 @@
    private int currentRound = 0;
    
    // 缓存层级对应的排序顺序
    private Dictionary<UILayer, int> layerSortingOrderCache = new Dictionary<UILayer, int>();
    private static Dictionary<UILayer, int> layerSortingOrderCache = new Dictionary<UILayer, int>();
    
    // 缓存层级对应的Transform
    private Dictionary<UILayer, Transform> layerTransformCache = new Dictionary<UILayer, Transform>();
@@ -64,23 +70,25 @@
    #endregion
    #region 初始化
    /// <summary>
    /// 初始化UI管理器
    /// </summary>
    public override void Init()
    {
        base.Init();
        // 初始化UI根节点
        InitUIRoot();
        // 初始化缓存
        layerSortingOrderCache.Clear();
        layerTransformCache.Clear();
        uiInstanceCounter.Clear();
        DOTween.SetTweensCapacity(500, 50);
        Debug.Log("UI管理器初始化完成");
    }
    
    /// <summary>
@@ -112,28 +120,33 @@
        staticTrans = uiRoot.Find("Static");
        bottomTrans = uiRoot.Find("Bottom");
        midTrans = uiRoot.Find("Middle");
        topTrans = uiRoot.Find("Top");
        loadingTrans = uiRoot.Find("Loading");
        systemTrans = uiRoot.Find("System");
        layerTransformCache.Clear();
        layerTransformCache.Add(UILayer.Static, staticTrans);
        layerTransformCache.Add(UILayer.Bottom, bottomTrans);
        layerTransformCache.Add(UILayer.Mid, midTrans);
        layerTransformCache.Add(UILayer.Top, topTrans);
        layerTransformCache.Add(UILayer.System, systemTrans);
        layerTransformCache.Add(UILayer.Loading, loadingTrans);
    }
    public Transform GetUIRoot()
    {
        return uiRoot;
    }
    
    #endregion
    #region 辅助方法
    // 获取UI层级对应的基础排序顺序
    private int GetBaseSortingOrderForLayer(UILayer layer)
    public static int GetBaseSortingOrderForLayer(UILayer layer)
    {
        // 尝试从缓存中获取排序顺序
        if (layerSortingOrderCache.TryGetValue(layer, out int order))
            return order;
        // 如果缓存中没有,使用原来的方法计算并缓存结果
        int result;
        switch (layer)
@@ -142,29 +155,29 @@
                result = BASE_SORTING_ORDER;
                break;
            case UILayer.Bottom:
                result = BASE_SORTING_ORDER * 10;
                break;
            case UILayer.Mid:
                result = BASE_SORTING_ORDER * 100;
                break;
            case UILayer.Top:
            case UILayer.Mid:
                result = BASE_SORTING_ORDER * 1000;
                break;
            case UILayer.System:
                result = BASE_SORTING_ORDER * 10000;
                result = BASE_SORTING_ORDER * 2000;
                break;
            case UILayer.Loading:
                result = BASE_SORTING_ORDER * 3000;
                break;
            default:
                result = BASE_SORTING_ORDER * 10;
                break;
        }
        // 将结果存入缓存
        layerSortingOrderCache[layer] = result;
        return result;
    }
    // 获取层级对应的Transform
    private Transform GetTransForLayer(UILayer layer)
    public Transform GetTransForLayer(UILayer layer)
    {
        // 尝试从缓存中获取Transform
        if (layerTransformCache.TryGetValue(layer, out Transform trans))
@@ -183,11 +196,11 @@
            case UILayer.Mid:
                result = midTrans;
                break;
            case UILayer.Top:
                result = topTrans;
                break;
            case UILayer.System:
                result = systemTrans;
                break;
            case UILayer.Loading:
                result = loadingTrans;
                break;
            default:
                result = bottomTrans;
@@ -216,6 +229,26 @@
        {
            // 返回第一个实例
            return uiList[0] as T;
        }
        // 如果不存在,返回null
        return null;
    }
    public UIBase GetUI(string uiName)
    {
        if (string.IsNullOrEmpty(uiName))
        {
            // 记录错误日志
            Debug.LogError("UI名称为空");
            return null;
        }
        // 尝试从字典中获取UI实例列表
        if (uiDict.TryGetValue(uiName, out List<UIBase> uiList) && uiList.Count > 0)
        {
            // 返回第一个实例
            return uiList[0];
        }
        // 如果不存在,返回null
@@ -280,6 +313,72 @@
        return false;
    }
    public bool IsOpened(string uiName)
    {
        UIBase ui = GetUI(uiName);
        if (null != ui)
        {
            return ui.IsActive();
        }
        return false;
    }
    // 检查是否存在任何全屏或遮罩窗口, 有screenMask 即可代表全屏
    public bool ExistAnyFullScreenOrMaskWin(string excludeUIName)
    {
        var exist = false;
        foreach (var uiList in uiDict.Values)
        {
            // 遍历该类型的所有UI实例
            foreach (var ui in uiList)
            {
                // 刷新UI
                if (ui.IsActive() && ui.name != excludeUIName)
                {
                    if (ui.screenMask != null)
                    {
                        exist = true;
                        break;
                    }
                }
            }
        }
        return exist;
    }
    //在此界面上有没任何全屏或遮罩窗口
    public bool ExistAnyFullScreenOrMaskWinAbove(string uiName)
    {
        var ui = GetUI(uiName);
        if (ui == null || !ui.IsActive())
        {
            // 如果UI不存在或未打开,默认为有被挡住
            return true;
        }
        foreach (var uiBase in uiStack)
        {
            if (uiBase == null)
            {
                continue;
            }
            if (uiBase.name == uiName)
            {
                break;
            }
            if (uiBase.IsActive() && uiBase.screenMask != null)
            {
                return true;
            }
        }
        return false;
    }
    
    // 获取指定类型的所有UI实例
    public List<T> GetAllUI<T>() where T : UIBase
@@ -423,7 +522,9 @@
        foreach (var ui in uiToClose)
        {
            // 记录日志
#if UNITY_EDITOR
            Debug.Log($"销毁长时间未使用的UI: {ui.uiName}, 空闲回合数: {currentRound - ui.lastUsedRound}");
#endif
            // 销毁UI对象
            GameObject.Destroy(ui.gameObject);
        }
@@ -451,8 +552,17 @@
    private UIBase LoadUIResource(string uiName)
    {
        // 从资源管理器加载UI预制体
        GameObject prefab = ResManager.Instance.LoadAsset<GameObject>("UI", uiName);
        GameObject prefab;
        if (uiName == "LaunchWin" || uiName == "DownLoadWin" || uiName == "RequestSecretWin" || uiName == "GameAgeWarnWin")
        {
            prefab = BuiltInLoader.LoadPrefab(uiName);
        }
        else
        {
            prefab = ResManager.Instance.LoadAsset<GameObject>("UI", uiName);
        }
        // 检查预制体是否加载成功
        if (prefab == null)
@@ -522,14 +632,19 @@
        uiStack.CopyTo(uiArray, 0);
        
        // 先按照UILayer进行排序,然后再按照栈顺序排序
        Array.Sort(uiArray, (a, b) => {
            // 比较UI层级
        Dictionary<UIBase, int> uiOrderDict = new Dictionary<UIBase, int>();
        for (int i = 0; i < uiArray.Length; i++)
        {
            uiOrderDict[uiArray[i]] = i;
        }
        Array.Sort(uiArray, (a, b) =>
        {
            int layerCompare = a.uiLayer.CompareTo(b.uiLayer);
            if (layerCompare != 0)
                return layerCompare;
            // 同层级内,按照栈中的顺序排序
            return Array.IndexOf(uiArray, a).CompareTo(Array.IndexOf(uiArray, b));
            return uiOrderDict[b].CompareTo(uiOrderDict[a]);
        });
        
        // 遍历排序后的UI数组,设置排序顺序
@@ -542,7 +657,9 @@
            // 设置UI的排序顺序
            ui.SetSortingOrder(sortingOrder);
            // 更新当前最高排序顺序
            currentHighestSortingOrder += 10;
            currentHighestSortingOrder += ui.uiLayer == UILayer.Static ? 155/*这里是角色+特效之上的层级*/ : 10;
            // Debug.Log(ui.uiName + " order is " + sortingOrder + " " + currentHighestSortingOrder);
        }
    }
    
@@ -554,39 +671,33 @@
    private UIBase GetLastSupportParentChildRelationUI()
    {
        List<UIBase> tempList = new List<UIBase>();
        UIBase target = null;
        while (target == null && uiStack.Count > 0)
        foreach (var uiBase in uiStack)
        {
            UIBase uiBase = uiStack.Pop();
            if (uiBase != null && uiBase.supportParentChildRelation && !uiBase.isMainUI)
            if (uiBase != null && uiBase.supportParentChildRelation)
            {
                target = uiBase;
                return uiBase;
            }
            tempList.Add(uiBase);
        }
        for (int i = tempList.Count - 1; i >= 0; i--)
        {
            uiStack.Push(tempList[i]);
        }
        return target;
        return null;
    }
    public UIBase OpenWindow(string uiName)
    public UIBase OpenWindow(string uiName, int functionOrder = 0)
    {
        // 优先从closedUIDict中获取
        UIBase parentUI = null;
        UIBase returnValue = null;
        if (closedUIDict.TryGetValue(uiName, out List<UIBase> closedUIList) && closedUIList.Count > 0)
        List<UIBase> closedUIList = new List<UIBase>();
        if (closedUIDict.TryGetValue(uiName, out closedUIList) && closedUIList.Count > 0)
        {
            #if UNITY_EDITOR
            Debug.Log("OpenWindow getFromClosedDict " + uiName);
            #endif
            returnValue = closedUIList[0] as UIBase;
            closedUIList.RemoveAt(0);
            
@@ -597,6 +708,9 @@
        }
        else
        {
            #if UNITY_EDITOR
            Debug.Log("OpenWindow getNewLoad " + uiName);
            #endif
            returnValue = LoadUIResource(uiName);
            if (returnValue == null)
            {
@@ -608,8 +722,8 @@
        
        returnValue.gameObject.SetActive(true);
        
        // 自动设置父级UI(如果未指定且支持父子关系)
        if (returnValue.supportParentChildRelation && uiStack.Count > 0)
        // 自动设置父级UI, 如果勾选了ismainui 则不需要找父级UI
        if (returnValue.supportParentChildRelation && uiStack.Count > 0 && !returnValue.isMainUI)
        {
            // 获取栈顶UI
            parentUI = GetLastSupportParentChildRelationUI();
@@ -644,7 +758,14 @@
        }
        // 添加到UI列表
        uiDict[uiName].Add(returnValue);
#if UNITY_EDITOR
        if (uiDict[uiName].Count > 5)
        {
            Debug.LogError("已打开" + uiDict[uiName].Count + "个界面:" + uiName);
        }
#endif
        // 将UI添加到栈中
        uiStack.Push(returnValue);
        
@@ -652,6 +773,7 @@
        UpdateUISortingOrder();
        
        // 打开UI
        returnValue.functionOrder = functionOrder;
        returnValue.HandleOpen();
        OnOpenWindow?.Invoke(returnValue);
@@ -665,11 +787,11 @@
    /// <summary>
    /// 打开UI
    /// </summary>
    public T OpenWindow<T>() where T : UIBase
    public T OpenWindow<T>(int functionOrder = 0) where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        return OpenWindow(uiName) as T;
        return OpenWindow(uiName, functionOrder) as T;
    }
    
    /// <summary>
@@ -721,7 +843,10 @@
        
        // 获取UI类型名称
        string uiName = ui.uiName;
#if UNITY_EDITOR
        Debug.Log("CloseWindow " + uiName + " destroy : " + destroy.ToString());
#endif
        // 收集所有子UI
        List<UIBase> childrenUI = new List<UIBase>();
        if (ui.supportParentChildRelation)
@@ -746,6 +871,10 @@
            if (tempUI != ui)
            {
                tempStack.Push(tempUI);
            }
            else
            {
                break;
            }
        }
        
@@ -777,7 +906,7 @@
        // 关闭UI
        ui.HandleClose();
        OnCloseWindow?.Invoke(ui);
        if (destroy)
        {
            // 销毁UI对象
@@ -791,9 +920,13 @@
                closedUIDict[uiName] = new List<UIBase>();
            }
            closedUIDict[uiName].Add(ui);
            // 隐藏UI
            ui.gameObject.SetActive(false);
#if UNITY_EDITOR
            Debug.Log("CloseWindow " + uiName + " destroy : " + destroy.ToString() + " push to closedUIDict");
#endif
            // 隐藏UI (交给handle close内部自己去做)
            // ui.gameObject.SetActive(false);
        }
        
        // 更新UI排序顺序
@@ -827,19 +960,6 @@
        }
    }
    public void ReturnMainUI()
    {
        List<UIBase> allUI = new List<UIBase>(uiStack);
        for (int i = 0; i < allUI.Count; i++)
        {
            UIBase uiBase = allUI[i];
            if (!uiBase.isMainUI && uiBase.uiLayer != UILayer.System)
            {
                CloseWindow(uiBase);
            }
        }
    }
    
    /// <summary>
    /// 关闭所有UI
@@ -857,6 +977,14 @@
            CloseWindow(ui, true);
        }
        
        foreach (var uiList in closedUIDict.Values)
        {
            foreach (var ui in uiList)
            {
                GameObject.Destroy(ui.gameObject);
            }
        }
        // 清空UI字典和栈
        uiDict.Clear();
        uiStack.Clear();