using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using Framework; using Obfuz; using PhxhSDK; using PhxhSDK.AOT.Aspect; using UnityEngine; [ObfuzIgnore] public partial class UIManager : Singlenton, IInitable, IUpdatable { public const string UI_PREFAB_PATH = "Assets/Art_Out/UI/Prefab/{0}.prefab"; public Dictionary mMemoryWindows = new Dictionary(); // ✅ 使用独立的层级管理器 private UICanvasLayerManager LayerManager => UICanvasLayerManager.Instance; private ScreenOrientation _currentOrientation; private Dictionary _openingWindows = new Dictionary(); private List _hideCache = new List(); private UIWindow _curFullScreen; private Dictionary _uiWindowObjDic = new Dictionary(); public Dictionary UIWindowObjDic => _uiWindowObjDic; public Vector2 Size; /// /// UI和主相机屏幕缩放 /// public Vector2 UIAndMainScreenScale; /// /// UI和UI屏幕缩放 /// public Vector2 UIAndUIScreenScale; /// /// 禁用返回键计数 /// private int disableBackCount; /// /// 是否响应返回键 /// public bool IsEnableBack { get { return disableBackCount <= 0; } set { if (value) { if (disableBackCount > 0) --disableBackCount; } else ++disableBackCount; } } public void Init() { IsEnableBack = true; _AllWindowMeta(); // 初始化层级管理器 LayerManager.Initialize(UIRoot.Instance.GetAllLayerRoots()); if (DeviceHelper.IsFullScreenIOS()) { SetFullScreenIOS(); } EventManager.Instance.Register(EventManager.EventName.Android_Click_Back, _OnAndroidClickBack); EventManager.Instance.Register(EventManager.EventName.ClearUIStack, (Action)ClearHideStack); OnScreenSizeChange(); AspectManager.Instance.ScreenSizeChange += OnScreenSizeChange; } public void Release() { LayerManager.Clear(); AspectManager.Instance.ScreenSizeChange -= OnScreenSizeChange; EventManager.Instance.Unregister(EventManager.EventName.Android_Click_Back, _OnAndroidClickBack); EventManager.Instance.Unregister(EventManager.EventName.ClearUIStack, (Action)ClearHideStack); } public bool disableUILogic = false; public void Update(float dt) { if (disableUILogic) return; foreach (var winKv in mMemoryWindows) { var window = winKv.Value; if (window != null && !window.IsClosing) { if (window.IsCreated() && window.gameObject) { if (window.gameObject) // todo:isShow { window.Update(dt); } } } } _UpdateInputBlockTimer(dt); } #region UIWindow Manager public static void BindWindowObj(UIWindow window, GameObject uiObj) { if (window == null || uiObj == null) { if (window == null) DebugUtil.LogError("window is null"); if (uiObj == null) DebugUtil.LogError("uiObj is null"); return; } window.gameObject = uiObj.gameObject; window.transform = uiObj.transform; window.name = uiObj.name; } #endregion #region OpenWindowAPI /// /// 打开一个UI /// UIManager.Instance.OpenWindow("Common/GameUI") /// /// /// 创建并打开窗口 /// /// 窗口路径 /// 传递的数据 public async UniTask CreateAndOpenWindow(string path, object data = null) { DebugUtil.LogP($"打开窗口:{path}"); if (mMemoryWindows.ContainsKey(path)) { DebugUtil.LogG($"窗口已打开!!!{path}"); //return null; } var window = await _LoadWindow(path, false); if (window != null) { // 初始化和显示窗口 window.Init(data); window.ShowWindow(data); // 获取配置 var config = GetWindowInfo(path); // 可见性管理 UIWindowVisibilityManager.Instance.HandleVisibilityOnOpen(window, config.VisibilityStrategy); } return window; } public bool Back() { return false; } public bool RemoveWindow(string wName) { string windowName = wName; bool result = false; UIWindow window; if (mMemoryWindows.TryGetValue(windowName, out window)) { LayerManager.RemoveWindow(window); mMemoryWindows.Remove(windowName); result = true; } return result; } /// /// 关闭窗口 /// /// 窗口名称 /// 是否销毁窗口 public void CloseWindow(string wName, bool destroy) { var window = GetOpenedWindowByPath(wName); if (window != null) { window.CloseWindow(destroy); } } /// /// 打开已加载的窗口(显示并根据配置处理) /// 适用于预加载窗口的显示场景 /// /// 已加载的窗口 /// 传递的数据(可选) public void OpenLoadedWindow(UIWindow window, object data = null) { if (window == null) { DebugUtil.LogError("OpenLoadedWindow: window is null"); return; } // 显示窗口 window.ShowWindow(data); // 获取配置 var config = GetWindowInfo(window.WindowName); // 可见性管理 UIWindowVisibilityManager.Instance.HandleVisibilityOnOpen(window, config.VisibilityStrategy); } /// /// 打开已加载的窗口(通过路径) /// public void OpenLoadedWindow(string path, object data = null) { var window = GetOpenedWindowByPath(path); if (window != null) { OpenLoadedWindow(window, data); } else { DebugUtil.LogError($"OpenLoadedWindow: window not found: {path}"); } } public T GetOpenedWindowByPath(string uipath) where T : UIWindow { var window = GetOpenedWindowByPath(uipath) as T; //return window.gameObject.activeSelf ? window : null; return window; } public UIWindow GetOpenedWindowByPath(string uipath) { if (string.IsNullOrEmpty(uipath)) { DebugUtil.LogError("UIManager.GetOpenedWindowByPath, uipath is null or empty"); return null; } if (mMemoryWindows.ContainsKey(uipath)) { //return window.gameObject.activeSelf ? window : null; return mMemoryWindows[uipath]; } return null; } public bool GetTopWindow(out UIWindow window, out UICanvasLayer layer, int banLayerMask) { return LayerManager.GetTopWindow(out window, out layer, banLayerMask); } public int LayerMask(UICanvasLayer layer) { return LayerManager.GetLayerMask(layer); } async void SetFullScreenIOS() { await UniTask.Delay(670); // while (true) // { // var screenOrientation = DragonNativeBridge.GetScreenOrientation(); // if (screenOrientation != _currentOrientation) // { // _currentOrientation = screenOrientation; // EventDispatcher.Instance.DispatchEvent(new ScreenOrientationChangedEvent(_currentOrientation)); // } // yield return wait; // } } /// /// 加载窗口(不显示) /// 用于预加载场景 /// public async UniTask LoadWindow(string path) { return await _LoadWindow(path, true); } private async UniTask _LoadWindow(string path, bool forceHide) { string uipath = path; UIWindow window = null; WindowInfo wInfo; if (!_windowsInfo.ContainsKey(uipath)) { //if (_windowsInfo.TryGetValue(uipath, out wInfo)) { DebugUtil.LogError("Create ui fail: {0}, no windows info inited", uipath); return window; } } wInfo = _windowsInfo[uipath]; var uiWindowLayer = wInfo.windowLayer; if (!mMemoryWindows.TryGetValue(uipath, out window)) { if (_openingWindows.ContainsKey(uipath)) { return window; } _openingWindows.Add(uipath, uipath); window = await UIRoot.Instance.CreateWindow(uipath, uiWindowLayer); _openingWindows.Remove(uipath); if (window != null) { mMemoryWindows[uipath] = window; window.WindowName = uipath; window.uiWindowLayer = uiWindowLayer; } else { DebugUtil.LogError("Create ui fail: {0}", uipath); return window; } } LayerManager.AddWindow(window); if (window == null) { DebugUtil.LogError("Create ui fail: {0}", uipath); return null; } if (forceHide) { window.gameObject.SetActive(false); } _uiWindowObjDic.TryAdd(window.gameObject, window); return window; } //展示全部已加载的NormalUI public void OpenLoadedNormalUI(string uiName, object data = null) { WindowInfo wInfo; wInfo = _windowsInfo[uiName]; if (mMemoryWindows.ContainsKey(uiName)) { mMemoryWindows[uiName].Init(data); mMemoryWindows[uiName].ShowWindow(data); } } public void ForeachUI(Action action) { var windowList = mMemoryWindows.ToList(); foreach (var kv in windowList) { var window = kv.Value; if (window != null) { action?.Invoke(kv.Value); } } } public void CloseAllUIExcept(string path) { var windowList = mMemoryWindows.ToList(); foreach (var kv in windowList) { var window = kv.Value; if(window.WindowName != path) { window.CloseWindow(destroy: true); mMemoryWindows.Remove(window.WindowName); LayerManager.RemoveWindow(window); } } } #endregion #region ShowAndHide /// /// 隐藏指定层级及以下的所有UI /// 和 ShowAllUI 成对调用 /// /// 最大层级(包含该层级及以下的所有UI都会被隐藏) /// 不隐藏的UI窗口名称列表 public void HideAllUI(UICanvasLayer maxLayer, params string[] exceptions) { var hiddenWindows = LayerManager.HideWindowsUpToLayer(maxLayer, exceptions); _hideCache.AddRange(hiddenWindows); } /// /// 和HideAllUI成对调用 /// public void ShowAllUI() { foreach (var v in _hideCache) { var window = v; if (window != null) window.ShowWindow(); } _hideCache.Clear(); } public async void ShowClickShield(string uiPath, int time = 0) { //放到最上层 if (!_windowsInfo.ContainsKey(uiPath)) { return; } CreateAndOpenWindow(uiPath); mMemoryWindows.TryGetValue(uiPath, out var window); if (time > 0) { await UniTask.Delay(time); window.CloseWindow(destroy: true); } } public void CloseClickShield(string uiPath) { if (mMemoryWindows.ContainsKey(uiPath)) { var window = mMemoryWindows[uiPath]; window.CloseWindow(destroy: true); } } #endregion //根据路径判断UI界面是否打开 public bool IsWindowOpening(string uiPath) { string windowName; if (_openingWindows.TryGetValue(uiPath, out windowName)) { if (windowName != null) { return true; } } return false; } /// /// 关闭指定层级的所有窗口(支持单个或多个层级) /// /// 要关闭的层级列表 public void CloseAllInLayer(params UICanvasLayer[] layers) { CloseAllInLayer(layers, null); } /// /// 关闭指定层级的所有窗口,可排除指定窗口(支持单个或多个层级) /// /// 要关闭的层级列表 /// 不关闭的窗口名称列表 public void CloseAllInLayer(UICanvasLayer[] layers, params string[] exceptions) { if (layers == null || layers.Length == 0) { DebugUtil.LogWarning("[CloseAllInLayer] No layers specified"); return; } int totalClosed = 0; foreach (var layer in layers) { var windowsInLayer = LayerManager.GetWindowsInLayer(layer); if (windowsInLayer.Count == 0) { DebugUtil.Log($"[CloseAllInLayer] No windows in layer: {layer}"); continue; } List toBeRemoved = new List(); var node = windowsInLayer.First; while (node != null) { var window = node.Value; bool shouldClose = true; // 检查是否在例外列表中 if (exceptions != null && exceptions.Length > 0) { foreach (var exception in exceptions) { if (window.WindowName == exception) { shouldClose = false; DebugUtil.Log($"[CloseAllInLayer] Skipping window: {window.WindowName} (in exception list)"); break; } } } if (shouldClose) { toBeRemoved.Add(window); } if (node == windowsInLayer.Last) { break; } node = node.Next; } // 关闭窗口 foreach (var window in toBeRemoved) { DebugUtil.Log($"[CloseAllInLayer] Closing window: {window.WindowName} in layer {layer}"); window.CloseWindow(destroy: true); } totalClosed += toBeRemoved.Count; } if (layers.Length == 1) DebugUtil.Log($"[CloseAllInLayer] Closed {totalClosed} windows in layer {layers[0]}"); else DebugUtil.Log($"[CloseAllInLayer] Closed {totalClosed} windows in {layers.Length} layers"); } private async void _OnAndroidClickBack() { if (!IsEnableBack) return; // 获取所有可见窗口(从上到下) var visibleWindows = LayerManager.GetAllVisibleWindows(); DebugUtil.Log($"[AndroidBack] Found {visibleWindows.Count} visible windows"); // 从上到下遍历,找到第一个处理返回键的窗口 foreach (var window in visibleWindows) { DebugUtil.Log($"[AndroidBack] Trying window: {window.WindowName} (Layer: {window.uiWindowLayer})"); if (await window.Back()) { // 窗口处理了返回键,结束遍历 DebugUtil.Log($"[AndroidBack] Handled by: {window.WindowName}"); return; } } // 没有窗口处理返回键,显示退出确认 DebugUtil.Log("[AndroidBack] No window handled, showing exit confirmation"); if (!CheckWindowCreated(UINameConst.UIBackReturn)) { await CreateAndOpenWindow(UINameConst.UIBackReturn); } } public bool CheckWindowCreated(string uiPath) { if (mMemoryWindows.TryGetValue(uiPath, out var window)) { return window.IsCreated(); } return false; } private async void OnScreenSizeChange() { await UniTask.NextFrame(); // 必须等待一帧,等RectTransform大小刷新后获取 RectTransform rectTrans = UIRoot.Instance.Root.GetComponent(); Size = new(rectTrans.sizeDelta.x, rectTrans.sizeDelta.y); UIAndMainScreenScale = new Vector3(Size.x / Screen.width, Size.y / Screen.height); UIAndUIScreenScale = new Vector3(Size.x / AspectManager.Instance.ScreenSize.x, Size.y / AspectManager.Instance.ScreenSize.y); } #region Navigation Stack Management /// /// 清空隐藏的窗口(除指定窗口外) /// public void ClearHideStack(params string[] windowName) { // 获取所有层级的窗口 var allWindows = new List(); for (int i = 0; i < (int)UICanvasLayer.Max; i++) { var layer = (UICanvasLayer)i; var windows = LayerManager.GetWindowsInLayer(layer); foreach (var window in windows) { if (!window.gameObject.activeSelf) // 只处理隐藏的窗口 { allWindows.Add(window); } } } // 关闭除指定窗口外的所有隐藏窗口 foreach (var window in allWindows) { bool shouldKeep = false; for (int j = 0; j < windowName.Length; j++) { if (window.WindowName == windowName[j]) { shouldKeep = true; break; } } if (!shouldKeep) { window.CloseWindow(destroy: true); } } } #endregion }