using System; 
 | 
using System.Collections; 
 | 
using System.Collections.Generic; 
 | 
using UnityEngine; 
 | 
using System.Linq; 
 | 
using DG.Tweening; 
 | 
  
 | 
/// <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 systemTrans; 
 | 
    private Transform loadingTrans; 
 | 
  
 | 
    // UI字典,存储所有已加载的UI,键为UI名称,值为UI实例 
 | 
#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>>(); 
 | 
  
 | 
    // UI栈,用于管理UI的显示顺序 
 | 
    private Stack<UIBase> uiStack = new Stack<UIBase>(); 
 | 
     
 | 
    // 当前最高的排序顺序 
 | 
    private int currentHighestSortingOrder = 0; 
 | 
     
 | 
    // 当前回合数,用于记录UI的使用情况 
 | 
    private int currentRound = 0; 
 | 
     
 | 
    // 缓存层级对应的排序顺序 
 | 
    private static 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(); 
 | 
  
 | 
        DOTween.SetTweensCapacity(500, 50); 
 | 
        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"); 
 | 
        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.System, systemTrans); 
 | 
        layerTransformCache.Add(UILayer.Loading, loadingTrans); 
 | 
    } 
 | 
     
 | 
    public Transform GetUIRoot() 
 | 
    { 
 | 
        return uiRoot; 
 | 
    } 
 | 
     
 | 
    #endregion 
 | 
  
 | 
    #region 辅助方法 
 | 
  
 | 
    // 获取UI层级对应的基础排序顺序 
 | 
    public static 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 * 100; 
 | 
                break; 
 | 
            case UILayer.Mid: 
 | 
                result = BASE_SORTING_ORDER * 1000; 
 | 
                break; 
 | 
            case UILayer.System: 
 | 
                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 
 | 
    public 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.System: 
 | 
                result = systemTrans; 
 | 
                break; 
 | 
            case UILayer.Loading: 
 | 
                result = loadingTrans; 
 | 
                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 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 
 | 
        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; 
 | 
    } 
 | 
  
 | 
    public bool IsOpened(string uiName) 
 | 
    { 
 | 
        UIBase ui = GetUI(uiName); 
 | 
  
 | 
        if (null != ui) 
 | 
        { 
 | 
            return ui.IsActive(); 
 | 
        } 
 | 
  
 | 
        return false; 
 | 
    } 
 | 
  
 | 
    // 检查是否存在任何全屏或遮罩窗口, 暂未定义全屏可以统一勾选openMask 
 | 
    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.openMask) 
 | 
                    { 
 | 
                        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.openMask) 
 | 
            { 
 | 
                return true; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        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) 
 | 
        { 
 | 
            // 记录日志 
 | 
#if UNITY_EDITOR 
 | 
            Debug.Log($"销毁长时间未使用的UI: {ui.uiName}, 空闲回合数: {currentRound - ui.lastUsedRound}"); 
 | 
#endif 
 | 
            // 销毁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; 
 | 
        if (uiName == "LaunchWin" || uiName == "DownLoadWin" || uiName == "RequestSecretWin" || uiName == "GameAgeWarnWin") 
 | 
        { 
 | 
            prefab = BuiltInLoader.LoadPrefab(uiName); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            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进行排序,然后再按照栈顺序排序 
 | 
        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 uiOrderDict[b].CompareTo(uiOrderDict[a]); 
 | 
        }); 
 | 
         
 | 
        // 遍历排序后的UI数组,设置排序顺序 
 | 
        foreach (var ui in uiArray) 
 | 
        { 
 | 
            // 获取基础排序顺序 
 | 
            int baseSortingOrder = GetBaseSortingOrderForLayer(ui.uiLayer); 
 | 
            // 计算当前UI的排序顺序 
 | 
            int sortingOrder = baseSortingOrder + currentHighestSortingOrder; 
 | 
            // 设置UI的排序顺序 
 | 
            ui.SetSortingOrder(sortingOrder); 
 | 
            // 更新当前最高排序顺序 
 | 
            currentHighestSortingOrder += ui.uiLayer == UILayer.Static ? 155/*这里是角色+特效之上的层级*/ : 10; 
 | 
  
 | 
            // Debug.Log(ui.uiName + " order is " + sortingOrder + " " + currentHighestSortingOrder); 
 | 
        } 
 | 
    } 
 | 
     
 | 
    #endregion 
 | 
  
 | 
    #region UI操作 
 | 
  
 | 
  
 | 
  
 | 
    private UIBase GetLastSupportParentChildRelationUI() 
 | 
    { 
 | 
  
 | 
        foreach (var uiBase in uiStack) 
 | 
        { 
 | 
            if (uiBase != null && uiBase.supportParentChildRelation) 
 | 
            { 
 | 
                return uiBase; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        return null; 
 | 
    } 
 | 
  
 | 
    public UIBase OpenWindow(string uiName, int functionOrder = 0) 
 | 
    { 
 | 
        // 优先从closedUIDict中获取 
 | 
        UIBase parentUI = null; 
 | 
  
 | 
        UIBase returnValue = null; 
 | 
  
 | 
        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); 
 | 
             
 | 
            if (closedUIList.Count == 0) 
 | 
            { 
 | 
                closedUIDict.Remove(uiName); 
 | 
            } 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            #if UNITY_EDITOR 
 | 
            Debug.Log("OpenWindow getNewLoad " + uiName); 
 | 
            #endif 
 | 
            returnValue = LoadUIResource(uiName); 
 | 
            if (returnValue == null) 
 | 
            { 
 | 
                // 记录错误日志 
 | 
                Debug.LogError($"打开UI失败: {uiName}"); 
 | 
                return null; 
 | 
            } 
 | 
        } 
 | 
         
 | 
        returnValue.gameObject.SetActive(true); 
 | 
         
 | 
        // 自动设置父级UI, 如果勾选了ismainui 则不需要找父级UI 
 | 
        if (returnValue.supportParentChildRelation && uiStack.Count > 0 && !returnValue.isMainUI) 
 | 
        { 
 | 
            // 获取栈顶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); 
 | 
  
 | 
#if UNITY_EDITOR 
 | 
        if (uiDict[uiName].Count > 5) 
 | 
        {  
 | 
            Debug.LogError("已打开" + uiDict[uiName].Count + "个界面:" + uiName); 
 | 
        } 
 | 
#endif 
 | 
  
 | 
        // 将UI添加到栈中 
 | 
        uiStack.Push(returnValue); 
 | 
         
 | 
        // 更新UI排序顺序 
 | 
        UpdateUISortingOrder(); 
 | 
         
 | 
        // 打开UI 
 | 
        returnValue.functionOrder = functionOrder; 
 | 
        returnValue.HandleOpen(); 
 | 
  
 | 
        OnOpenWindow?.Invoke(returnValue); 
 | 
         
 | 
        // 检查并关闭长时间未使用的UI 
 | 
        CheckAndCloseIdleUI(); 
 | 
         
 | 
        return returnValue; 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 打开UI 
 | 
    /// </summary> 
 | 
    public T OpenWindow<T>(int functionOrder = 0) where T : UIBase 
 | 
    { 
 | 
        // 获取UI类型名称 
 | 
        string uiName = typeof(T).Name; 
 | 
        return OpenWindow(uiName, functionOrder) 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; 
 | 
        } 
 | 
  
 | 
        if (!ui.IsActive()) 
 | 
        { 
 | 
            return; 
 | 
        } 
 | 
         
 | 
        // 获取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) 
 | 
        { 
 | 
            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); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                break; 
 | 
            } 
 | 
        } 
 | 
         
 | 
        // 将临时栈中的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); 
 | 
  
 | 
#if UNITY_EDITOR 
 | 
            Debug.Log("CloseWindow " + uiName + " destroy : " + destroy.ToString() + " push to closedUIDict"); 
 | 
#endif 
 | 
  
 | 
            // 隐藏UI (交给handle close内部自己去做) 
 | 
            // 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); 
 | 
        } 
 | 
         
 | 
        foreach (var uiList in closedUIDict.Values) 
 | 
        { 
 | 
            foreach (var ui in uiList) 
 | 
            { 
 | 
                GameObject.Destroy(ui.gameObject); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        // 清空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 
 | 
} 
 |