yyl
2025-06-04 a7f4c5ecc5268c49f6a6caf769b3ebee6f237662
Main/Manager/UIManager.cs
File was renamed from Main/UI/UIManager.cs
@@ -1,921 +1,921 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
/// <summary>
/// UI管理器 - 负责管理所有UI界面的显示、隐藏和层级
/// </summary>
public class UIManager : ManagerBase<UIManager>
{
    #region 常量和枚举
    // 基础排序顺序
    private const int BASE_SORTING_ORDER = 10;
    #endregion
    #region 字段和属性
    // UI根节点
    private Transform uiRoot;
    // 各层级的Transform
    private Transform staticTrans;
    private Transform bottomTrans;
    private Transform midTrans;
    private Transform topTrans;
    private Transform systemTrans;
    // UI字典,存储所有已加载的UI,键为UI名称,值为UI实例
    private Dictionary<string, List<UIBase>> uiDict = new Dictionary<string, List<UIBase>>();
    // 存储关闭但未销毁的UI,键为UI名称,值为UI实例
    private Dictionary<string, List<UIBase>> closedUIDict = new Dictionary<string, List<UIBase>>();
    // UI栈,用于管理UI的显示顺序
    private Stack<UIBase> uiStack = new Stack<UIBase>();
    // 当前最高的排序顺序
    private int currentHighestSortingOrder = 0;
    // 当前回合数,用于记录UI的使用情况
    private int currentRound = 0;
    // 缓存层级对应的排序顺序
    private Dictionary<UILayer, int> layerSortingOrderCache = new Dictionary<UILayer, int>();
    // 缓存层级对应的Transform
    private Dictionary<UILayer, Transform> layerTransformCache = new Dictionary<UILayer, Transform>();
    // UI实例计数器,用于为同类型UI生成唯一标识
    private Dictionary<string, int> uiInstanceCounter = new Dictionary<string, int>();
    // 上次检查时间
    private float lastCheckTime = 0f;
    // 检查间隔(秒)
    private const float CHECK_INTERVAL = 5f;
    public Action<UIBase> OnOpenWindow;
    public Action<UIBase> OnCloseWindow;
    #endregion
    #region 初始化
    /// <summary>
    /// 初始化UI管理器
    /// </summary>
    public override void Init()
    {
        base.Init();
        // 初始化UI根节点
        InitUIRoot();
        // 初始化缓存
        layerSortingOrderCache.Clear();
        layerTransformCache.Clear();
        uiInstanceCounter.Clear();
        Debug.Log("UI管理器初始化完成");
    }
    /// <summary>
    /// 初始化UI根节点
    /// </summary>
    private void InitUIRoot()
    {
        // 查找UI根节点
        GameObject root = GameObject.Find("UIRoot");
        // 如果场景中没有UI根节点,则创建一个
        if (root == null)
        {
            root = GameObject.Instantiate(BuiltInLoader.LoadPrefab("UIRoot"));
            root.name = "UIRoot";
            if (root == null)
            {
                Debug.LogError("无法找到UI根节点");
                return;
            }
            // 添加DontDestroyOnLoad组件,确保UI根节点在场景切换时不被销毁
            GameObject.DontDestroyOnLoad(root);
        }
        uiRoot = root.transform;
        uiRoot.position = Vector3.zero;
        staticTrans = uiRoot.Find("Static");
        bottomTrans = uiRoot.Find("Bottom");
        midTrans = uiRoot.Find("Middle");
        topTrans = uiRoot.Find("Top");
        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);
    }
    #endregion
    #region 辅助方法
    // 获取UI层级对应的基础排序顺序
    private int GetBaseSortingOrderForLayer(UILayer layer)
    {
        // 尝试从缓存中获取排序顺序
        if (layerSortingOrderCache.TryGetValue(layer, out int order))
            return order;
        // 如果缓存中没有,使用原来的方法计算并缓存结果
        int result;
        switch (layer)
        {
            case UILayer.Static:
                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:
                result = BASE_SORTING_ORDER * 1000;
                break;
            case UILayer.System:
                result = BASE_SORTING_ORDER * 10000;
                break;
            default:
                result = BASE_SORTING_ORDER * 10;
                break;
        }
        // 将结果存入缓存
        layerSortingOrderCache[layer] = result;
        return result;
    }
    // 获取层级对应的Transform
    private Transform GetTransForLayer(UILayer layer)
    {
        // 尝试从缓存中获取Transform
        if (layerTransformCache.TryGetValue(layer, out Transform trans))
            return trans;
        // 如果缓存中没有,使用原来的方法获取并缓存结果
        Transform result;
        switch (layer)
        {
            case UILayer.Static:
                result = staticTrans;
                break;
            case UILayer.Bottom:
                result = bottomTrans;
                break;
            case UILayer.Mid:
                result = midTrans;
                break;
            case UILayer.Top:
                result = topTrans;
                break;
            case UILayer.System:
                result = systemTrans;
                break;
            default:
                result = bottomTrans;
                break;
        }
        // 将结果存入缓存
        layerTransformCache[layer] = result;
        return result;
    }
    // 获取UI实例,如果不存在则返回null
    public T GetUI<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        if (string.IsNullOrEmpty(uiName))
        {
            // 记录错误日志
            Debug.LogError("UI名称为空");
            return null;
        }
        // 尝试从字典中获取UI实例列表
        if (uiDict.TryGetValue(uiName, out List<UIBase> uiList) && uiList.Count > 0)
        {
            // 返回第一个实例
            return uiList[0] as T;
        }
        // 如果不存在,返回null
        return null;
    }
    public List<T> GetUIList<T>() where T : UIBase
    {
        List<T> uiList = new List<T>();
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        if (string.IsNullOrEmpty(uiName))
        {
            // 记录错误日志
            Debug.LogError("UI名称为空");
            return uiList;
        }
        // 尝试从字典中获取UI实例列表
        List<UIBase> tempList = null;
        uiDict.TryGetValue(uiName, out tempList);
        if (tempList != null)
        {
            for (int i = 0; i < tempList.Count; i++)
            {
                UIBase ui = tempList[i];
                if (null != ui)
                {
                    uiList.Add(ui as T);
                }
            }
        }
        return uiList;
    }
    public bool IsOpenedInList<T>() where T : UIBase
    {
        List<T> uiList = GetUIList<T>();
        foreach (T ui in uiList)
        {
            if (ui.IsActive())
            {
                return true;
            }
        }
        return false;
    }
    public bool IsOpened<T>() where T : UIBase
    {
        T ui = GetUI<T>();
        if (null != ui)
        {
            return ui.IsActive();
        }
        return false;
    }
    // 获取指定类型的所有UI实例
    public List<T> GetAllUI<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        if (string.IsNullOrEmpty(uiName))
        {
            // 记录错误日志
            Debug.LogError("UI名称为空");
            return new List<T>();
        }
        // 尝试从字典中获取UI实例列表
        if (uiDict.TryGetValue(uiName, out List<UIBase> uiList) && uiList.Count > 0)
        {
            // 将列表中的所有实例转换为指定类型并返回
            return uiList.Cast<T>().ToList();
        }
        // 如果不存在,返回空列表
        return new List<T>();
    }
    // 更新父级UI的回合数
    private void UpdateParentUIRounds(UIBase ui)
    {
        // 如果UI为空或不支持父子关系,直接返回
        if (ui == null || !ui.supportParentChildRelation)
            return;
        // 获取父级UI
        UIBase parentUI = ui.parentUI;
        // 遍历所有父级UI,更新回合数
        while (parentUI != null)
        {
            // 更新父级UI的最后使用回合数
            parentUI.lastUsedRound = currentRound;
            // 继续向上查找父级UI
            parentUI = parentUI.parentUI;
        }
    }
    // 递归收集所有子UI
    private void CollectChildrenUI(UIBase ui, List<UIBase> result)
    {
        // 如果UI为空或没有子UI或不支持父子关系,直接返回
        if (ui == null || !ui.supportParentChildRelation || ui.childrenUI == null || ui.childrenUI.Count == 0)
            return;
        // 遍历所有子UI
        foreach (var childUI in ui.childrenUI)
        {
            // 如果结果列表中不包含当前子UI,则添加
            if (!result.Contains(childUI))
            {
                // 添加到结果列表
                result.Add(childUI);
                // 递归收集子UI的子UI
                CollectChildrenUI(childUI, result);
            }
        }
    }
    /// <summary>
    /// 检查并关闭长时间未使用的UI
    /// </summary>
    public void CheckAndCloseIdleUI()
    {
        // 如果没有UI,直接返回
        if (uiDict.Count == 0 && closedUIDict.Count == 0)
            return;
        // 创建需要关闭的UI列表
        List<UIBase> uiToClose = new List<UIBase>();
        // 遍历所有活跃UI
        foreach (var uiList in uiDict.Values)
        {
            foreach (var ui in uiList)
            {
                // 如果UI是持久化的,跳过
                if (ui.isPersistent)
                    continue;
                if (ui.IsActive())
                    continue;
                // 计算UI空闲的回合数
                int idleRounds = currentRound - ui.lastUsedRound;
                // 如果空闲回合数超过最大空闲回合数,添加到关闭列表
                if (idleRounds > ui.maxIdleRounds)
                {
                    uiToClose.Add(ui);
                }
            }
        }
        // 遍历所有关闭的UI
        List<string> emptyKeys = new List<string>();
        foreach (var kvp in closedUIDict)
        {
            string uiName = kvp.Key;
            List<UIBase> uiList = kvp.Value;
            List<UIBase> uiToRemove = new List<UIBase>();
            foreach (var ui in uiList)
            {
                // 计算UI空闲的回合数
                int idleRounds = currentRound - ui.lastUsedRound;
                // 如果空闲回合数超过最大空闲回合数,添加到关闭列表
                if (idleRounds > ui.maxIdleRounds)
                {
                    uiToClose.Add(ui);
                    uiToRemove.Add(ui);
                }
            }
            // 从关闭列表中移除需要销毁的UI
            foreach (var ui in uiToRemove)
            {
                uiList.Remove(ui);
            }
            // 如果列表为空,记录需要从字典中移除的键
            if (uiList.Count == 0)
            {
                emptyKeys.Add(uiName);
            }
        }
        // 从字典中移除空列表
        foreach (var key in emptyKeys)
        {
            closedUIDict.Remove(key);
        }
        // 销毁所有需要关闭的UI
        foreach (var ui in uiToClose)
        {
            // 记录日志
            Debug.Log($"销毁长时间未使用的UI: {ui.uiName}, 空闲回合数: {currentRound - ui.lastUsedRound}");
            // 销毁UI对象
            GameObject.Destroy(ui.gameObject);
        }
    }
    // // 生成UI实例的唯一标识
    // private string GenerateUIInstanceID(string uiName)
    // {
    //     // 如果计数器中不存在该UI类型,初始化为0
    //     if (!uiInstanceCounter.ContainsKey(uiName))
    //     {
    //         uiInstanceCounter[uiName] = 0;
    //     }
    //     // 递增计数器
    //     uiInstanceCounter[uiName]++;
    //     // 返回带有计数的唯一标识
    //     return $"{uiName}_{uiInstanceCounter[uiName]}";
    // }
    #endregion
    #region UI资源管理
    private UIBase LoadUIResource(string uiName)
    {
        // 从资源管理器加载UI预制体
        GameObject prefab = ResManager.Instance.LoadAsset<GameObject>("UI", uiName);
        // 检查预制体是否加载成功
        if (prefab == null)
        {
            // 记录错误日志
            Debug.LogError($"加载UI预制体失败: {uiName}");
            return null;
        }
        // 实例化UI对象
        GameObject uiObject = GameObject.Instantiate(prefab);
        // 设置对象名称
        uiObject.name = uiName;
        // 通过uiName映射Type
        Type uiType = Type.GetType(uiName);
        if (uiType == null)
        {
            Debug.LogError($"找不到UI类型: {uiName}");
            return null;
        }
        // 获取UI基类组件
        UIBase uiBase = uiObject.GetComponent(uiType) as UIBase;
        // 检查UI基类组件是否存在
        if (uiBase == null)
        {
            // 记录错误日志
            Debug.LogError($"UI预制体 {uiName} 没有 UIBase 组件或类型不匹配");
            return null;
        }
        // 设置UI名称
        uiBase.uiName = uiName;
        // 设置父节点为UI根节点
        Transform parentTrans = GetTransForLayer(uiBase.uiLayer);
        uiObject.transform.SetParent(parentTrans, false);
        // 设置排序顺序
        int baseSortingOrder = GetBaseSortingOrderForLayer(uiBase.uiLayer);
        uiBase.SetSortingOrder(baseSortingOrder);
        return uiBase;
    }
    // 加载UI预制体
    private T LoadUIResource<T>(string uiName) where T : UIBase
    {
        return LoadUIResource(uiName) as T;
    }
    #endregion
    #region UI排序管理
    // 更新UI排序顺序
    private void UpdateUISortingOrder()
    {
        // 重置当前最高排序顺序
        currentHighestSortingOrder = 0;
        // 遍历UI栈,设置排序顺序
        UIBase[] uiArray = new UIBase[uiStack.Count];
        uiStack.CopyTo(uiArray, 0);
        // 先按照UILayer进行排序,然后再按照栈顺序排序
        Array.Sort(uiArray, (a, b) => {
            // 比较UI层级
            int layerCompare = a.uiLayer.CompareTo(b.uiLayer);
            if (layerCompare != 0)
                return layerCompare;
            // 同层级内,按照栈中的顺序排序
            return Array.IndexOf(uiArray, a).CompareTo(Array.IndexOf(uiArray, b));
        });
        // 遍历排序后的UI数组,设置排序顺序
        foreach (var ui in uiArray)
        {
            // 获取基础排序顺序
            int baseSortingOrder = GetBaseSortingOrderForLayer(ui.uiLayer);
            // 计算当前UI的排序顺序
            int sortingOrder = baseSortingOrder + currentHighestSortingOrder;
            // 设置UI的排序顺序
            ui.SetSortingOrder(sortingOrder);
            // 更新当前最高排序顺序
            currentHighestSortingOrder += 10;
        }
    }
    #endregion
    #region UI操作
    private UIBase GetLastSupportParentChildRelationUI()
    {
        List<UIBase> tempList = new List<UIBase>();
        UIBase target = null;
        while (target == null && uiStack.Count > 0)
        {
            UIBase uiBase = uiStack.Pop();
            if (uiBase != null && uiBase.supportParentChildRelation && !uiBase.isMainUI)
            {
                target = uiBase;
            }
            tempList.Add(uiBase);
        }
        for (int i = tempList.Count - 1; i >= 0; i--)
        {
            uiStack.Push(tempList[i]);
        }
        return target;
    }
    public UIBase OpenWindow(string uiName)
    {
        // 优先从closedUIDict中获取
        UIBase parentUI = null;
        UIBase returnValue = null;
        if (closedUIDict.TryGetValue(uiName, out List<UIBase> closedUIList) && closedUIList.Count > 0)
        {
            returnValue = closedUIList[0] as UIBase;
            closedUIList.RemoveAt(0);
            if (closedUIList.Count == 0)
            {
                closedUIDict.Remove(uiName);
            }
        }
        else
        {
            returnValue = LoadUIResource(uiName);
            if (returnValue == null)
            {
                // 记录错误日志
                Debug.LogError($"打开UI失败: {uiName}");
                return null;
            }
        }
        returnValue.gameObject.SetActive(true);
        // 自动设置父级UI(如果未指定且支持父子关系)
        if (returnValue.supportParentChildRelation && uiStack.Count > 0)
        {
            // 获取栈顶UI
            parentUI = GetLastSupportParentChildRelationUI();
        }
        // 设置父级UI
        if (parentUI != null)
        {
            // 设置父子关系
            returnValue.parentUI = parentUI;
            if (parentUI.childrenUI == null)
            {
                // 初始化父级UI的子UI列表
                parentUI.childrenUI = new List<UIBase>();
            }
            // 添加到父级UI的子UI列表
            parentUI.childrenUI.Add(returnValue);
        }
        // 更新回合数
        currentRound++;
        // 设置UI的最后使用回合数
        returnValue.lastUsedRound = currentRound;
        // 更新父级UI的回合数
        UpdateParentUIRounds(returnValue);
        // 将UI添加到字典中
        if (!uiDict.ContainsKey(uiName))
        {
            // 如果字典中不存在该类型的UI,创建新列表
            uiDict[uiName] = new List<UIBase>();
        }
        // 添加到UI列表
        uiDict[uiName].Add(returnValue);
        // 将UI添加到栈中
        uiStack.Push(returnValue);
        // 更新UI排序顺序
        UpdateUISortingOrder();
        // 打开UI
        returnValue.HandleOpen();
        OnOpenWindow?.Invoke(returnValue);
        // 检查并关闭长时间未使用的UI
        CheckAndCloseIdleUI();
        return returnValue;
    }
    /// <summary>
    /// 打开UI
    /// </summary>
    public T OpenWindow<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        return OpenWindow(uiName) as T;
    }
    /// <summary>
    /// 关闭UI
    /// </summary>
    public void CloseWindow<T>(bool destroy = false) where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        CloseWindow(uiName, destroy);
    }
    public void CloseWindow(string uiName, bool destroy = false)
    {
        // 检查UI是否存在
        if (!uiDict.ContainsKey(uiName) || uiDict[uiName].Count == 0)
        {
            // 记录警告日志
            Debug.LogWarning($"尝试关闭不存在的UI: {uiName}");
            return;
        }
        // 获取第一个UI实例
        UIBase ui = uiDict[uiName][0];
        // 关闭UI
        CloseWindow(ui, destroy);
    }
    /// <summary>
    /// 关闭指定的UI实例
    /// </summary>
    public void CloseWindow(UIBase ui, bool destroy = false)
    {
        // 检查UI是否为空
        if (ui == null)
        {
            // 记录警告日志
            Debug.LogWarning("尝试关闭空UI");
            return;
        }
        // 获取UI类型名称
        string uiName = ui.uiName;
        // 收集所有子UI
        List<UIBase> childrenUI = new List<UIBase>();
        if (ui.supportParentChildRelation)
        {
            CollectChildrenUI(ui, childrenUI);
        }
        // 先关闭所有子UI
        foreach (var childUI in childrenUI)
        {
            // 关闭子UI
            CloseWindow(childUI, destroy);
        }
        // 从栈中移除UI
        Stack<UIBase> tempStack = new Stack<UIBase>();
        while (uiStack.Count > 0)
        {
            // 弹出栈顶UI
            UIBase tempUI = uiStack.Pop();
            // 如果不是要关闭的UI,则保存到临时栈中
            if (tempUI != ui)
            {
                tempStack.Push(tempUI);
            }
        }
        // 将临时栈中的UI重新压入栈中
        while (tempStack.Count > 0)
        {
            uiStack.Push(tempStack.Pop());
        }
        // 从字典中移除UI
        if (uiDict.ContainsKey(uiName))
        {
            // 从UI列表中移除
            uiDict[uiName].Remove(ui);
            // 如果列表为空,从字典中移除该类型
            if (uiDict[uiName].Count == 0)
            {
                uiDict.Remove(uiName);
            }
        }
        // 从父级UI的子UI列表中移除
        if (ui.supportParentChildRelation && ui.parentUI != null && ui.parentUI.childrenUI != null)
        {
            // 从父级UI的子UI列表中移除
            ui.parentUI.childrenUI.Remove(ui);
        }
        // 关闭UI
        ui.HandleClose();
        OnCloseWindow?.Invoke(ui);
        if (destroy)
        {
            // 销毁UI对象
            GameObject.Destroy(ui.gameObject);
        }
        else
        {
            // 添加到closedUIDict
            if (!closedUIDict.ContainsKey(uiName))
            {
                closedUIDict[uiName] = new List<UIBase>();
            }
            closedUIDict[uiName].Add(ui);
            // 隐藏UI
            ui.gameObject.SetActive(false);
        }
        // 更新UI排序顺序
        UpdateUISortingOrder();
    }
    /// <summary>
    /// 关闭指定类型的所有UI实例
    /// </summary>
    public void CloseAllWindows<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        // 检查UI是否存在
        if (!uiDict.ContainsKey(uiName) || uiDict[uiName].Count == 0)
        {
            // 记录警告日志
            Debug.LogWarning($"尝试关闭不存在的UI: {uiName}");
            return;
        }
        // 创建UI实例列表的副本,因为在关闭过程中会修改原列表
        List<UIBase> uiListCopy = new List<UIBase>(uiDict[uiName]);
        // 关闭所有UI实例
        foreach (var ui in uiListCopy)
        {
            // 关闭UI实例
            CloseWindow(ui, false);
        }
    }
    /// <summary>
    /// 关闭所有UI
    /// </summary>
    public void DestroyAllUI()
    {
        // 创建UI栈的副本,因为在关闭过程中会修改原栈
        UIBase[] uiArray = new UIBase[uiStack.Count];
        uiStack.CopyTo(uiArray, 0);
        // 关闭所有UI
        foreach (var ui in uiArray)
        {
            // 关闭UI
            CloseWindow(ui, true);
        }
        // 清空UI字典和栈
        uiDict.Clear();
        uiStack.Clear();
        closedUIDict.Clear();
    }
    /// <summary>
    /// 刷新UI
    /// </summary>
    public void RefreshUI<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        // 检查UI是否存在
        if (!uiDict.ContainsKey(uiName) || uiDict[uiName].Count == 0)
        {
            // 记录警告日志
            Debug.LogWarning($"尝试刷新不存在的UI: {uiName}");
            return;
        }
        // 刷新所有该类型的UI实例
        foreach (var ui in uiDict[uiName])
        {
            // 刷新UI
            ui.Refresh();
        }
    }
    /// <summary>
    /// 刷新所有UI
    /// </summary>
    public void RefreshAllUI()
    {
        // 遍历所有UI类型
        foreach (var uiList in uiDict.Values)
        {
            // 遍历该类型的所有UI实例
            foreach (var ui in uiList)
            {
                // 刷新UI
                ui.Refresh();
            }
        }
    }
    private void Update()
    {
        // 如果距离上次检查的时间超过了检查间隔
        if (Time.time - lastCheckTime > CHECK_INTERVAL)
        {
            // 更新上次检查时间
            lastCheckTime = Time.time;
            // 检查并关闭长时间未使用的UI
            CheckAndCloseIdleUI();
        }
    }
    #endregion
    #region 释放资源
    /// <summary>
    /// 释放资源
    /// </summary>
    public override void Release()
    {
        // 关闭所有UI
        DestroyAllUI();
        // 清空缓存
        layerSortingOrderCache.Clear();
        layerTransformCache.Clear();
        uiInstanceCounter.Clear();
        Debug.Log("UI管理器资源释放完成");
    }
    #endregion
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
/// <summary>
/// UI管理器 - 负责管理所有UI界面的显示、隐藏和层级
/// </summary>
public class UIManager : ManagerBase<UIManager>
{
    #region 常量和枚举
    // 基础排序顺序
    private const int BASE_SORTING_ORDER = 10;
    #endregion
    #region 字段和属性
    // UI根节点
    private Transform uiRoot;
    // 各层级的Transform
    private Transform staticTrans;
    private Transform bottomTrans;
    private Transform midTrans;
    private Transform topTrans;
    private Transform systemTrans;
    // UI字典,存储所有已加载的UI,键为UI名称,值为UI实例
    private Dictionary<string, List<UIBase>> uiDict = new Dictionary<string, List<UIBase>>();
    // 存储关闭但未销毁的UI,键为UI名称,值为UI实例
    private Dictionary<string, List<UIBase>> closedUIDict = new Dictionary<string, List<UIBase>>();
    // UI栈,用于管理UI的显示顺序
    private Stack<UIBase> uiStack = new Stack<UIBase>();
    // 当前最高的排序顺序
    private int currentHighestSortingOrder = 0;
    // 当前回合数,用于记录UI的使用情况
    private int currentRound = 0;
    // 缓存层级对应的排序顺序
    private Dictionary<UILayer, int> layerSortingOrderCache = new Dictionary<UILayer, int>();
    // 缓存层级对应的Transform
    private Dictionary<UILayer, Transform> layerTransformCache = new Dictionary<UILayer, Transform>();
    // UI实例计数器,用于为同类型UI生成唯一标识
    private Dictionary<string, int> uiInstanceCounter = new Dictionary<string, int>();
    // 上次检查时间
    private float lastCheckTime = 0f;
    // 检查间隔(秒)
    private const float CHECK_INTERVAL = 5f;
    public Action<UIBase> OnOpenWindow;
    public Action<UIBase> OnCloseWindow;
    #endregion
    #region 初始化
    /// <summary>
    /// 初始化UI管理器
    /// </summary>
    public override void Init()
    {
        base.Init();
        // 初始化UI根节点
        InitUIRoot();
        // 初始化缓存
        layerSortingOrderCache.Clear();
        layerTransformCache.Clear();
        uiInstanceCounter.Clear();
        Debug.Log("UI管理器初始化完成");
    }
    /// <summary>
    /// 初始化UI根节点
    /// </summary>
    private void InitUIRoot()
    {
        // 查找UI根节点
        GameObject root = GameObject.Find("UIRoot");
        // 如果场景中没有UI根节点,则创建一个
        if (root == null)
        {
            root = GameObject.Instantiate(BuiltInLoader.LoadPrefab("UIRoot"));
            root.name = "UIRoot";
            if (root == null)
            {
                Debug.LogError("无法找到UI根节点");
                return;
            }
            // 添加DontDestroyOnLoad组件,确保UI根节点在场景切换时不被销毁
            GameObject.DontDestroyOnLoad(root);
        }
        uiRoot = root.transform;
        uiRoot.position = Vector3.zero;
        staticTrans = uiRoot.Find("Static");
        bottomTrans = uiRoot.Find("Bottom");
        midTrans = uiRoot.Find("Middle");
        topTrans = uiRoot.Find("Top");
        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);
    }
    #endregion
    #region 辅助方法
    // 获取UI层级对应的基础排序顺序
    private int GetBaseSortingOrderForLayer(UILayer layer)
    {
        // 尝试从缓存中获取排序顺序
        if (layerSortingOrderCache.TryGetValue(layer, out int order))
            return order;
        // 如果缓存中没有,使用原来的方法计算并缓存结果
        int result;
        switch (layer)
        {
            case UILayer.Static:
                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:
                result = BASE_SORTING_ORDER * 1000;
                break;
            case UILayer.System:
                result = BASE_SORTING_ORDER * 10000;
                break;
            default:
                result = BASE_SORTING_ORDER * 10;
                break;
        }
        // 将结果存入缓存
        layerSortingOrderCache[layer] = result;
        return result;
    }
    // 获取层级对应的Transform
    private Transform GetTransForLayer(UILayer layer)
    {
        // 尝试从缓存中获取Transform
        if (layerTransformCache.TryGetValue(layer, out Transform trans))
            return trans;
        // 如果缓存中没有,使用原来的方法获取并缓存结果
        Transform result;
        switch (layer)
        {
            case UILayer.Static:
                result = staticTrans;
                break;
            case UILayer.Bottom:
                result = bottomTrans;
                break;
            case UILayer.Mid:
                result = midTrans;
                break;
            case UILayer.Top:
                result = topTrans;
                break;
            case UILayer.System:
                result = systemTrans;
                break;
            default:
                result = bottomTrans;
                break;
        }
        // 将结果存入缓存
        layerTransformCache[layer] = result;
        return result;
    }
    // 获取UI实例,如果不存在则返回null
    public T GetUI<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        if (string.IsNullOrEmpty(uiName))
        {
            // 记录错误日志
            Debug.LogError("UI名称为空");
            return null;
        }
        // 尝试从字典中获取UI实例列表
        if (uiDict.TryGetValue(uiName, out List<UIBase> uiList) && uiList.Count > 0)
        {
            // 返回第一个实例
            return uiList[0] as T;
        }
        // 如果不存在,返回null
        return null;
    }
    public List<T> GetUIList<T>() where T : UIBase
    {
        List<T> uiList = new List<T>();
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        if (string.IsNullOrEmpty(uiName))
        {
            // 记录错误日志
            Debug.LogError("UI名称为空");
            return uiList;
        }
        // 尝试从字典中获取UI实例列表
        List<UIBase> tempList = null;
        uiDict.TryGetValue(uiName, out tempList);
        if (tempList != null)
        {
            for (int i = 0; i < tempList.Count; i++)
            {
                UIBase ui = tempList[i];
                if (null != ui)
                {
                    uiList.Add(ui as T);
                }
            }
        }
        return uiList;
    }
    public bool IsOpenedInList<T>() where T : UIBase
    {
        List<T> uiList = GetUIList<T>();
        foreach (T ui in uiList)
        {
            if (ui.IsActive())
            {
                return true;
            }
        }
        return false;
    }
    public bool IsOpened<T>() where T : UIBase
    {
        T ui = GetUI<T>();
        if (null != ui)
        {
            return ui.IsActive();
        }
        return false;
    }
    // 获取指定类型的所有UI实例
    public List<T> GetAllUI<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        if (string.IsNullOrEmpty(uiName))
        {
            // 记录错误日志
            Debug.LogError("UI名称为空");
            return new List<T>();
        }
        // 尝试从字典中获取UI实例列表
        if (uiDict.TryGetValue(uiName, out List<UIBase> uiList) && uiList.Count > 0)
        {
            // 将列表中的所有实例转换为指定类型并返回
            return uiList.Cast<T>().ToList();
        }
        // 如果不存在,返回空列表
        return new List<T>();
    }
    // 更新父级UI的回合数
    private void UpdateParentUIRounds(UIBase ui)
    {
        // 如果UI为空或不支持父子关系,直接返回
        if (ui == null || !ui.supportParentChildRelation)
            return;
        // 获取父级UI
        UIBase parentUI = ui.parentUI;
        // 遍历所有父级UI,更新回合数
        while (parentUI != null)
        {
            // 更新父级UI的最后使用回合数
            parentUI.lastUsedRound = currentRound;
            // 继续向上查找父级UI
            parentUI = parentUI.parentUI;
        }
    }
    // 递归收集所有子UI
    private void CollectChildrenUI(UIBase ui, List<UIBase> result)
    {
        // 如果UI为空或没有子UI或不支持父子关系,直接返回
        if (ui == null || !ui.supportParentChildRelation || ui.childrenUI == null || ui.childrenUI.Count == 0)
            return;
        // 遍历所有子UI
        foreach (var childUI in ui.childrenUI)
        {
            // 如果结果列表中不包含当前子UI,则添加
            if (!result.Contains(childUI))
            {
                // 添加到结果列表
                result.Add(childUI);
                // 递归收集子UI的子UI
                CollectChildrenUI(childUI, result);
            }
        }
    }
    /// <summary>
    /// 检查并关闭长时间未使用的UI
    /// </summary>
    public void CheckAndCloseIdleUI()
    {
        // 如果没有UI,直接返回
        if (uiDict.Count == 0 && closedUIDict.Count == 0)
            return;
        // 创建需要关闭的UI列表
        List<UIBase> uiToClose = new List<UIBase>();
        // 遍历所有活跃UI
        foreach (var uiList in uiDict.Values)
        {
            foreach (var ui in uiList)
            {
                // 如果UI是持久化的,跳过
                if (ui.isPersistent)
                    continue;
                if (ui.IsActive())
                    continue;
                // 计算UI空闲的回合数
                int idleRounds = currentRound - ui.lastUsedRound;
                // 如果空闲回合数超过最大空闲回合数,添加到关闭列表
                if (idleRounds > ui.maxIdleRounds)
                {
                    uiToClose.Add(ui);
                }
            }
        }
        // 遍历所有关闭的UI
        List<string> emptyKeys = new List<string>();
        foreach (var kvp in closedUIDict)
        {
            string uiName = kvp.Key;
            List<UIBase> uiList = kvp.Value;
            List<UIBase> uiToRemove = new List<UIBase>();
            foreach (var ui in uiList)
            {
                // 计算UI空闲的回合数
                int idleRounds = currentRound - ui.lastUsedRound;
                // 如果空闲回合数超过最大空闲回合数,添加到关闭列表
                if (idleRounds > ui.maxIdleRounds)
                {
                    uiToClose.Add(ui);
                    uiToRemove.Add(ui);
                }
            }
            // 从关闭列表中移除需要销毁的UI
            foreach (var ui in uiToRemove)
            {
                uiList.Remove(ui);
            }
            // 如果列表为空,记录需要从字典中移除的键
            if (uiList.Count == 0)
            {
                emptyKeys.Add(uiName);
            }
        }
        // 从字典中移除空列表
        foreach (var key in emptyKeys)
        {
            closedUIDict.Remove(key);
        }
        // 销毁所有需要关闭的UI
        foreach (var ui in uiToClose)
        {
            // 记录日志
            Debug.Log($"销毁长时间未使用的UI: {ui.uiName}, 空闲回合数: {currentRound - ui.lastUsedRound}");
            // 销毁UI对象
            GameObject.Destroy(ui.gameObject);
        }
    }
    // // 生成UI实例的唯一标识
    // private string GenerateUIInstanceID(string uiName)
    // {
    //     // 如果计数器中不存在该UI类型,初始化为0
    //     if (!uiInstanceCounter.ContainsKey(uiName))
    //     {
    //         uiInstanceCounter[uiName] = 0;
    //     }
    //     // 递增计数器
    //     uiInstanceCounter[uiName]++;
    //     // 返回带有计数的唯一标识
    //     return $"{uiName}_{uiInstanceCounter[uiName]}";
    // }
    #endregion
    #region UI资源管理
    private UIBase LoadUIResource(string uiName)
    {
        // 从资源管理器加载UI预制体
        GameObject prefab = ResManager.Instance.LoadAsset<GameObject>("UI", uiName);
        // 检查预制体是否加载成功
        if (prefab == null)
        {
            // 记录错误日志
            Debug.LogError($"加载UI预制体失败: {uiName}");
            return null;
        }
        // 实例化UI对象
        GameObject uiObject = GameObject.Instantiate(prefab);
        // 设置对象名称
        uiObject.name = uiName;
        // 通过uiName映射Type
        Type uiType = Type.GetType(uiName);
        if (uiType == null)
        {
            Debug.LogError($"找不到UI类型: {uiName}");
            return null;
        }
        // 获取UI基类组件
        UIBase uiBase = uiObject.GetComponent(uiType) as UIBase;
        // 检查UI基类组件是否存在
        if (uiBase == null)
        {
            // 记录错误日志
            Debug.LogError($"UI预制体 {uiName} 没有 UIBase 组件或类型不匹配");
            return null;
        }
        // 设置UI名称
        uiBase.uiName = uiName;
        // 设置父节点为UI根节点
        Transform parentTrans = GetTransForLayer(uiBase.uiLayer);
        uiObject.transform.SetParent(parentTrans, false);
        // 设置排序顺序
        int baseSortingOrder = GetBaseSortingOrderForLayer(uiBase.uiLayer);
        uiBase.SetSortingOrder(baseSortingOrder);
        return uiBase;
    }
    // 加载UI预制体
    private T LoadUIResource<T>(string uiName) where T : UIBase
    {
        return LoadUIResource(uiName) as T;
    }
    #endregion
    #region UI排序管理
    // 更新UI排序顺序
    private void UpdateUISortingOrder()
    {
        // 重置当前最高排序顺序
        currentHighestSortingOrder = 0;
        // 遍历UI栈,设置排序顺序
        UIBase[] uiArray = new UIBase[uiStack.Count];
        uiStack.CopyTo(uiArray, 0);
        // 先按照UILayer进行排序,然后再按照栈顺序排序
        Array.Sort(uiArray, (a, b) => {
            // 比较UI层级
            int layerCompare = a.uiLayer.CompareTo(b.uiLayer);
            if (layerCompare != 0)
                return layerCompare;
            // 同层级内,按照栈中的顺序排序
            return Array.IndexOf(uiArray, a).CompareTo(Array.IndexOf(uiArray, b));
        });
        // 遍历排序后的UI数组,设置排序顺序
        foreach (var ui in uiArray)
        {
            // 获取基础排序顺序
            int baseSortingOrder = GetBaseSortingOrderForLayer(ui.uiLayer);
            // 计算当前UI的排序顺序
            int sortingOrder = baseSortingOrder + currentHighestSortingOrder;
            // 设置UI的排序顺序
            ui.SetSortingOrder(sortingOrder);
            // 更新当前最高排序顺序
            currentHighestSortingOrder += 10;
        }
    }
    #endregion
    #region UI操作
    private UIBase GetLastSupportParentChildRelationUI()
    {
        List<UIBase> tempList = new List<UIBase>();
        UIBase target = null;
        while (target == null && uiStack.Count > 0)
        {
            UIBase uiBase = uiStack.Pop();
            if (uiBase != null && uiBase.supportParentChildRelation && !uiBase.isMainUI)
            {
                target = uiBase;
            }
            tempList.Add(uiBase);
        }
        for (int i = tempList.Count - 1; i >= 0; i--)
        {
            uiStack.Push(tempList[i]);
        }
        return target;
    }
    public UIBase OpenWindow(string uiName)
    {
        // 优先从closedUIDict中获取
        UIBase parentUI = null;
        UIBase returnValue = null;
        if (closedUIDict.TryGetValue(uiName, out List<UIBase> closedUIList) && closedUIList.Count > 0)
        {
            returnValue = closedUIList[0] as UIBase;
            closedUIList.RemoveAt(0);
            if (closedUIList.Count == 0)
            {
                closedUIDict.Remove(uiName);
            }
        }
        else
        {
            returnValue = LoadUIResource(uiName);
            if (returnValue == null)
            {
                // 记录错误日志
                Debug.LogError($"打开UI失败: {uiName}");
                return null;
            }
        }
        returnValue.gameObject.SetActive(true);
        // 自动设置父级UI(如果未指定且支持父子关系)
        if (returnValue.supportParentChildRelation && uiStack.Count > 0)
        {
            // 获取栈顶UI
            parentUI = GetLastSupportParentChildRelationUI();
        }
        // 设置父级UI
        if (parentUI != null)
        {
            // 设置父子关系
            returnValue.parentUI = parentUI;
            if (parentUI.childrenUI == null)
            {
                // 初始化父级UI的子UI列表
                parentUI.childrenUI = new List<UIBase>();
            }
            // 添加到父级UI的子UI列表
            parentUI.childrenUI.Add(returnValue);
        }
        // 更新回合数
        currentRound++;
        // 设置UI的最后使用回合数
        returnValue.lastUsedRound = currentRound;
        // 更新父级UI的回合数
        UpdateParentUIRounds(returnValue);
        // 将UI添加到字典中
        if (!uiDict.ContainsKey(uiName))
        {
            // 如果字典中不存在该类型的UI,创建新列表
            uiDict[uiName] = new List<UIBase>();
        }
        // 添加到UI列表
        uiDict[uiName].Add(returnValue);
        // 将UI添加到栈中
        uiStack.Push(returnValue);
        // 更新UI排序顺序
        UpdateUISortingOrder();
        // 打开UI
        returnValue.HandleOpen();
        OnOpenWindow?.Invoke(returnValue);
        // 检查并关闭长时间未使用的UI
        CheckAndCloseIdleUI();
        return returnValue;
    }
    /// <summary>
    /// 打开UI
    /// </summary>
    public T OpenWindow<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        return OpenWindow(uiName) as T;
    }
    /// <summary>
    /// 关闭UI
    /// </summary>
    public void CloseWindow<T>(bool destroy = false) where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        CloseWindow(uiName, destroy);
    }
    public void CloseWindow(string uiName, bool destroy = false)
    {
        // 检查UI是否存在
        if (!uiDict.ContainsKey(uiName) || uiDict[uiName].Count == 0)
        {
            // 记录警告日志
            Debug.LogWarning($"尝试关闭不存在的UI: {uiName}");
            return;
        }
        // 获取第一个UI实例
        UIBase ui = uiDict[uiName][0];
        // 关闭UI
        CloseWindow(ui, destroy);
    }
    /// <summary>
    /// 关闭指定的UI实例
    /// </summary>
    public void CloseWindow(UIBase ui, bool destroy = false)
    {
        // 检查UI是否为空
        if (ui == null)
        {
            // 记录警告日志
            Debug.LogWarning("尝试关闭空UI");
            return;
        }
        // 获取UI类型名称
        string uiName = ui.uiName;
        // 收集所有子UI
        List<UIBase> childrenUI = new List<UIBase>();
        if (ui.supportParentChildRelation)
        {
            CollectChildrenUI(ui, childrenUI);
        }
        // 先关闭所有子UI
        foreach (var childUI in childrenUI)
        {
            // 关闭子UI
            CloseWindow(childUI, destroy);
        }
        // 从栈中移除UI
        Stack<UIBase> tempStack = new Stack<UIBase>();
        while (uiStack.Count > 0)
        {
            // 弹出栈顶UI
            UIBase tempUI = uiStack.Pop();
            // 如果不是要关闭的UI,则保存到临时栈中
            if (tempUI != ui)
            {
                tempStack.Push(tempUI);
            }
        }
        // 将临时栈中的UI重新压入栈中
        while (tempStack.Count > 0)
        {
            uiStack.Push(tempStack.Pop());
        }
        // 从字典中移除UI
        if (uiDict.ContainsKey(uiName))
        {
            // 从UI列表中移除
            uiDict[uiName].Remove(ui);
            // 如果列表为空,从字典中移除该类型
            if (uiDict[uiName].Count == 0)
            {
                uiDict.Remove(uiName);
            }
        }
        // 从父级UI的子UI列表中移除
        if (ui.supportParentChildRelation && ui.parentUI != null && ui.parentUI.childrenUI != null)
        {
            // 从父级UI的子UI列表中移除
            ui.parentUI.childrenUI.Remove(ui);
        }
        // 关闭UI
        ui.HandleClose();
        OnCloseWindow?.Invoke(ui);
        if (destroy)
        {
            // 销毁UI对象
            GameObject.Destroy(ui.gameObject);
        }
        else
        {
            // 添加到closedUIDict
            if (!closedUIDict.ContainsKey(uiName))
            {
                closedUIDict[uiName] = new List<UIBase>();
            }
            closedUIDict[uiName].Add(ui);
            // 隐藏UI
            ui.gameObject.SetActive(false);
        }
        // 更新UI排序顺序
        UpdateUISortingOrder();
    }
    /// <summary>
    /// 关闭指定类型的所有UI实例
    /// </summary>
    public void CloseAllWindows<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        // 检查UI是否存在
        if (!uiDict.ContainsKey(uiName) || uiDict[uiName].Count == 0)
        {
            // 记录警告日志
            Debug.LogWarning($"尝试关闭不存在的UI: {uiName}");
            return;
        }
        // 创建UI实例列表的副本,因为在关闭过程中会修改原列表
        List<UIBase> uiListCopy = new List<UIBase>(uiDict[uiName]);
        // 关闭所有UI实例
        foreach (var ui in uiListCopy)
        {
            // 关闭UI实例
            CloseWindow(ui, false);
        }
    }
    /// <summary>
    /// 关闭所有UI
    /// </summary>
    public void DestroyAllUI()
    {
        // 创建UI栈的副本,因为在关闭过程中会修改原栈
        UIBase[] uiArray = new UIBase[uiStack.Count];
        uiStack.CopyTo(uiArray, 0);
        // 关闭所有UI
        foreach (var ui in uiArray)
        {
            // 关闭UI
            CloseWindow(ui, true);
        }
        // 清空UI字典和栈
        uiDict.Clear();
        uiStack.Clear();
        closedUIDict.Clear();
    }
    /// <summary>
    /// 刷新UI
    /// </summary>
    public void RefreshUI<T>() where T : UIBase
    {
        // 获取UI类型名称
        string uiName = typeof(T).Name;
        // 检查UI是否存在
        if (!uiDict.ContainsKey(uiName) || uiDict[uiName].Count == 0)
        {
            // 记录警告日志
            Debug.LogWarning($"尝试刷新不存在的UI: {uiName}");
            return;
        }
        // 刷新所有该类型的UI实例
        foreach (var ui in uiDict[uiName])
        {
            // 刷新UI
            ui.Refresh();
        }
    }
    /// <summary>
    /// 刷新所有UI
    /// </summary>
    public void RefreshAllUI()
    {
        // 遍历所有UI类型
        foreach (var uiList in uiDict.Values)
        {
            // 遍历该类型的所有UI实例
            foreach (var ui in uiList)
            {
                // 刷新UI
                ui.Refresh();
            }
        }
    }
    private void Update()
    {
        // 如果距离上次检查的时间超过了检查间隔
        if (Time.time - lastCheckTime > CHECK_INTERVAL)
        {
            // 更新上次检查时间
            lastCheckTime = Time.time;
            // 检查并关闭长时间未使用的UI
            CheckAndCloseIdleUI();
        }
    }
    #endregion
    #region 释放资源
    /// <summary>
    /// 释放资源
    /// </summary>
    public override void Release()
    {
        // 关闭所有UI
        DestroyAllUI();
        // 清空缓存
        layerSortingOrderCache.Clear();
        layerTransformCache.Clear();
        uiInstanceCounter.Clear();
        Debug.Log("UI管理器资源释放完成");
    }
    #endregion
}