NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Framework/UI/UICanvasLayerManager.cs

299 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// UI Canvas 层级管理器
/// 负责管理 UI 窗口的层级关系、排序和可见性控制
/// </summary>
public class UICanvasLayerManager
{
#region Singleton
private static UICanvasLayerManager _instance;
public static UICanvasLayerManager Instance
{
get
{
if (_instance == null)
{
_instance = new UICanvasLayerManager();
}
return _instance;
}
}
private UICanvasLayerManager() { }
#endregion
#region Fields
/// <summary>
/// UICanvasLayer 到 sortingOrder 的映射
/// </summary>
private static readonly Dictionary<UICanvasLayer, int> LayerToSortingOrderMap = new Dictionary<UICanvasLayer, int>
{
{ UICanvasLayer.BackGround, 100 },
{ UICanvasLayer.Normal, 200 },
{ UICanvasLayer.ForeGround, 300 },
{ UICanvasLayer.Tips, 400 },
{ UICanvasLayer.Guide, 500 },
{ UICanvasLayer.System, 600 },
};
/// <summary>
/// 每个层级的窗口列表
/// Key: UICanvasLayer 的整数值
/// Value: 该层级的窗口链表
/// </summary>
private Dictionary<int, LinkedList<UIWindow>> _layerWindowLists = new Dictionary<int, LinkedList<UIWindow>>(16);
#endregion
#region Initialization
/// <summary>
/// 初始化:为每个 Canvas 设置 sortingOrder
/// </summary>
/// <param name="rootDic">UI层级根节点字典</param>
public void Initialize(IReadOnlyDictionary<UICanvasLayer, GameObject> rootDic)
{
if (rootDic == null)
{
DebugUtil.LogError("[UICanvasLayerManager] Initialize failed: rootDic is null");
return;
}
foreach (var kv in LayerToSortingOrderMap)
{
var layer = kv.Key;
if (rootDic.TryGetValue(layer, out var rootGo))
{
var canvas = rootGo.GetComponent<Canvas>();
if (canvas != null)
{
canvas.overrideSorting = true;
canvas.sortingOrder = kv.Value;
DebugUtil.Log($"[UICanvasLayerManager] Set {rootGo.name} sortingOrder = {canvas.sortingOrder} for layer {layer}");
}
else
{
DebugUtil.LogWarning($"[UICanvasLayerManager] {rootGo.name} has no Canvas component!");
}
}
else
{
DebugUtil.LogWarning($"[UICanvasLayerManager] Cannot find Canvas for layer: {layer}");
}
}
}
/// <summary>
/// 清理所有数据
/// </summary>
public void Clear()
{
_layerWindowLists.Clear();
}
#endregion
#region Window Management
/// <summary>
/// 将窗口添加到指定层级
/// </summary>
public void AddWindow(UIWindow window)
{
if (window == null) return;
var layer = (int)window.uiWindowLayer;
if (!_layerWindowLists.TryGetValue(layer, out var windowList))
{
windowList = new LinkedList<UIWindow>();
_layerWindowLists.Add(layer, windowList);
}
// 移除已存在的(避免重复)
windowList.Remove(window);
// 添加到列表末尾(最上层)
windowList.AddLast(window);
// 设置 SiblingIndex只在同层级内排序
window.transform.SetAsLastSibling();
}
/// <summary>
/// 从层级中移除窗口
/// </summary>
public void RemoveWindow(UIWindow window)
{
if (window == null) return;
var layer = (int)window.uiWindowLayer;
if (_layerWindowLists.TryGetValue(layer, out var windowList))
{
windowList.Remove(window);
}
}
#endregion
#region Query
/// <summary>
/// 获取指定层级的所有窗口
/// </summary>
public LinkedList<UIWindow> GetWindowsInLayer(UICanvasLayer layer)
{
if (_layerWindowLists.TryGetValue((int)layer, out var windowList))
{
return windowList;
}
return new LinkedList<UIWindow>();
}
/// <summary>
/// 获取指定层级的最上层窗口
/// </summary>
public UIWindow GetTopWindowInLayer(UICanvasLayer layer)
{
if (_layerWindowLists.TryGetValue((int)layer, out var windowList) && windowList.Count > 0)
{
return windowList.Last.Value;
}
return null;
}
/// <summary>
/// 获取所有层级的顶部窗口(从高到低遍历)
/// </summary>
public bool GetTopWindow(out UIWindow window, out UICanvasLayer layer, int banLayerMask = 0)
{
for (int i = (int)UICanvasLayer.Max - 1; i >= 0; i--)
{
if (((1 << i) & banLayerMask) == 0)
{
if (_layerWindowLists.TryGetValue(i, out var windowList) && windowList.Count > 0)
{
window = windowList.Last.Value;
if (window != null)
{
layer = (UICanvasLayer)i;
return true;
}
}
}
}
window = null;
layer = UICanvasLayer.Max;
return false;
}
/// <summary>
/// 获取所有可见窗口列表(从最上层到最下层)
/// </summary>
/// <returns>按显示优先级排序的可见窗口列表</returns>
public List<UIWindow> GetAllVisibleWindows()
{
var visibleWindows = new List<UIWindow>();
// 从最高层级到最低层级遍历
for (int i = (int)UICanvasLayer.Max - 1; i >= 0; i--)
{
if (_layerWindowLists.TryGetValue(i, out var windowList))
{
// 从链表尾到头(最上层到最下层)遍历该层级的窗口
var node = windowList.Last;
while (node != null)
{
var window = node.Value;
// 检查窗口是否逻辑上可见(未关闭、未销毁、且处于显示状态)
if (window != null &&
!window.IsClosing &&
window.gameObject != null &&
window.IsShow())
{
visibleWindows.Add(window);
}
node = node.Previous;
}
}
}
return visibleWindows;
}
#endregion
#region Visibility Control
/// <summary>
/// 隐藏指定层级及以下的所有窗口
/// </summary>
public List<UIWindow> HideWindowsUpToLayer(UICanvasLayer maxLayer, params string[] exceptions)
{
var hiddenWindows = new List<UIWindow>();
for (int i = 0; i <= (int)maxLayer; i++)
{
HideWindowsInLayerInternal((UICanvasLayer)i, hiddenWindows, exceptions);
}
return hiddenWindows;
}
/// <summary>
/// 隐藏指定层级列表中的所有窗口
/// </summary>
public List<UIWindow> HideWindowsInLayers(UICanvasLayer[] layers, params string[] exceptions)
{
var hiddenWindows = new List<UIWindow>();
foreach (var layer in layers)
{
HideWindowsInLayerInternal(layer, hiddenWindows, exceptions);
}
return hiddenWindows;
}
/// <summary>
/// 隐藏单个层级的所有窗口(内部方法)
/// </summary>
private void HideWindowsInLayerInternal(UICanvasLayer layer, List<UIWindow> hiddenWindows, string[] exceptions)
{
if (_layerWindowLists.TryGetValue((int)layer, out var windowList))
{
foreach (var window in windowList)
{
if (window.gameObject.activeInHierarchy && !IsException(window.WindowName, exceptions))
{
hiddenWindows.Add(window);
window.CloseWindow(destroy:false);
}
}
}
}
/// <summary>
/// 检查窗口是否在例外列表中
/// </summary>
private bool IsException(string windowName, string[] exceptions)
{
if (exceptions == null || exceptions.Length == 0) return false;
foreach (var exception in exceptions)
{
if (exception == windowName) return true;
}
return false;
}
#endregion
#region Utilities
/// <summary>
/// 获取层级掩码
/// </summary>
public int GetLayerMask(UICanvasLayer layer)
{
return 1 << ((int)layer);
}
#endregion
}