hch
2025-09-15 5119041cf7042a6681c4df44437b282472733d77
Main/Manager/UIManager.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using DG.Tweening;
/// <summary>
/// UI管理器 - 负责管理所有UI界面的显示、隐藏和层级
@@ -29,8 +30,13 @@
    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>>();
@@ -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>
@@ -148,10 +156,10 @@
                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 * 100000;
                result = BASE_SORTING_ORDER * 3000;
                break;
            default:
                result = BASE_SORTING_ORDER * 10;
@@ -216,6 +224,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
@@ -423,7 +451,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 +481,17 @@
    private UIBase LoadUIResource(string uiName)
    {
        // 从资源管理器加载UI预制体
        GameObject prefab = ResManager.Instance.LoadAsset<GameObject>("UI", uiName);
        GameObject prefab;
        if (uiName == "LaunchWin")
        {
            prefab = BuiltInLoader.LoadPrefab(uiName);
        }
        else
        {
            prefab = ResManager.Instance.LoadAsset<GameObject>("UI", uiName);
        }
        // 检查预制体是否加载成功
        if (prefab == null)
@@ -522,14 +561,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, b).CompareTo(Array.IndexOf(uiArray, a));
            return uiOrderDict[b].CompareTo(uiOrderDict[a]);
        });
        
        // 遍历排序后的UI数组,设置排序顺序
@@ -580,20 +624,20 @@
        return target;
    }
    public UIBase OpenWindow(string uiName)
    public UIBase OpenWindow(string uiName, int functionOrder = 0)
    {
        // 优先从closedUIDict中获取
        UIBase parentUI = null;
        UIBase returnValue = null;
        Debug.Log("OpenWindow " + uiName);
        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);
@@ -605,7 +649,9 @@
        }
        else
        {
            #if UNITY_EDITOR
            Debug.Log("OpenWindow getNewLoad " + uiName);
            #endif
            returnValue = LoadUIResource(uiName);
            if (returnValue == null)
            {
@@ -653,7 +699,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);
        
@@ -661,6 +714,7 @@
        UpdateUISortingOrder();
        
        // 打开UI
        returnValue.functionOrder = functionOrder;
        returnValue.HandleOpen();
        OnOpenWindow?.Invoke(returnValue);
@@ -674,11 +728,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>
@@ -730,8 +784,9 @@
        
        // 获取UI类型名称
        string uiName = ui.uiName;
#if UNITY_EDITOR
        Debug.Log("CloseWindow " + uiName + " destroy : " + destroy.ToString());
#endif
        // 收集所有子UI
        List<UIBase> childrenUI = new List<UIBase>();
@@ -788,7 +843,7 @@
        // 关闭UI
        ui.HandleClose();
        OnCloseWindow?.Invoke(ui);
        if (destroy)
        {
            // 销毁UI对象
@@ -802,8 +857,10 @@
                closedUIDict[uiName] = new List<UIBase>();
            }
            closedUIDict[uiName].Add(ui);
#if UNITY_EDITOR
            Debug.Log("CloseWindow " + uiName + " destroy : " + destroy.ToString() + " push to closedUIDict");
#endif
            // 隐藏UI (交给handle close内部自己去做)
            // ui.gameObject.SetActive(false);