using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using Framework; using PhxhSDK; using PhxhSDK.AOT.Aspect; using UnityEngine; 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 Dictionary> _layerList = new Dictionary>(16); 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; /// /// 是否响应返回键 /// public bool IsEnableBack { get; set; } public void Init() { IsEnableBack = true; _AllWindowMeta(); if (DeviceHelper.IsFullScreenIOS()) { SetFullScreenIOS(); } EventManager.Instance.Register(EventManager.EventName.Android_Click_Back, _OnAndroidClickBack); EventManager.Instance.Register(EventManager.EventName.HideAllUIExcept, (Action)_OnHideAllUIExcept); EventManager.Instance.Register(EventManager.EventName.ShowAllUIHiden, _OnShowAllUIHiden); EventManager.Instance.Register(EventManager.EventName.ClearUIStack, (Action)ClearHideStack); OnScreenSizeChange(); AspectManager.Instance.ScreenSizeChange += OnScreenSizeChange; } public void Release() { AspectManager.Instance.ScreenSizeChange -= OnScreenSizeChange; EventManager.Instance.Unregister(EventManager.EventName.Android_Click_Back, _OnAndroidClickBack); EventManager.Instance.Unregister(EventManager.EventName.HideAllUIExcept, (Action)_OnHideAllUIExcept); EventManager.Instance.Unregister(EventManager.EventName.ShowAllUIHiden, _OnShowAllUIHiden); EventManager.Instance.Unregister(EventManager.EventName.ClearUIStack, (Action)ClearHideStack); } public void Update(float dt) { foreach (var winKv in mMemoryWindows) { var window = winKv.Value; if (window != null && !window.IsClosing) { if (window.IsCreated() && window.gameObject) { window.Update(); window.Update(dt); } } } _OnClickUpdate(dt); } #region UIWindow Manager public static void BindWindowObj(UIWindow window, GameObject uiObj) { window.gameObject = uiObj.gameObject; window.transform = uiObj.transform; window.rectTransform = uiObj.GetComponent(); window.name = uiObj.name; } #endregion #region OpenWindowAPI /// /// 打开一个UI /// UIManager.Instance.OpenWindow("Common/GameUI") /// //重载一下,传参的Open public async UniTask CreateAndOpenWindow(string path, object data = null, ECanvasRoot eCanvasRoot = ECanvasRoot.Static1) { DebugUtil.LogP($"打开窗口:{path}"); if (mMemoryWindows.ContainsKey(path)) { DebugUtil.LogG($"窗口已打开!!!{path}"); //return null; } var root = UIRoot.Instance.RootDic[eCanvasRoot]; var window = await _LoadWindow(path, true, eCanvasRoot); if (window != null) { if (window.uiWindowLayer == UIWindowLayer.Normal) { if (CheckWindowIsFullScreen(window)) { int idx = _uiWindowStack.Count - 1; while (idx >= 0) { var latestWindow = _uiWindowStack[idx--]; latestWindow.CloseWindow(UIWindowCloseType.HideAndPush); if (CheckWindowIsFullScreen(latestWindow)) { break; } } } } for (int i = root.transform.childCount - 1; i >=0; i--) { var winGo = root.transform.GetChild(i).gameObject; if (_uiWindowObjDic.TryGetValue(winGo, out var win)) { if (win != null) { if (win.uiWindowLayer > window.uiWindowLayer) { window.transform.SetSiblingIndex(i); } } } } window.CreateWindow(data, GetIsNotSetCameraByPath(path)); if (window.uiWindowLayer == UIWindowLayer.Normal) { PushWindow(window); } } return window; } //先打开后关闭 // public async UniTask CreateAndOpenWindow(string path, object data = null) // { // if (mMemoryWindows.ContainsKey(path)) // { // DebugUtil.LogError($"窗口已打开!!!{path}"); // //return null; // } // // var window = await _LoadWindow(path, true); // if (window != null) // { // var root = UIRoot.Instance.Root; // for (int i = root.transform.childCount - 1; i >=0; i--) // { // var winGo = root.transform.GetChild(i).gameObject; // if (_uiWindowObjDic.TryGetValue(winGo, out var win)) // { // if (win != null) // { // if (win.uiWindowLayer > window.uiWindowLayer) // { // window.transform.SetSiblingIndex(i); // } // } // } // } // window.CreateWindow(data, GetIsNotSetCameraByPath(path)); // // if (window.uiWindowLayer == UIWindowLayer.Normal) // { // if (CheckWindowIsFullScreen(window)) // { // int idx = _uiWindowStack.Count - 1; // while (idx >= 0) // { // var latestWindow = _uiWindowStack[idx--]; // var bNotSet = latestWindow.IsNotSetMainCamera; // latestWindow.IsNotSetMainCamera = true; // latestWindow.CloseWindow(UIWindowCloseType.HideAndPush); // latestWindow.IsNotSetMainCamera = bNotSet; // if (CheckWindowIsFullScreen(latestWindow)) // { // break; // } // } // } // // } // // if (window.uiWindowLayer == UIWindowLayer.Normal) // { // PushWindow(window); // } // // } // // 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)) { LayerListRemoveWindow(window); mMemoryWindows.Remove(windowName); result = true; } return result; } public void CloseWindow(string wName, UIWindowCloseType closeType = UIWindowCloseType.HideAndDestroy, int playAnim = 0) { var window = GetOpenedWindowByPath(wName); if (window != null) { window.CloseWindow(closeType, playAnim); } } 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; } void LayerListInsertWindow(UIWindow window) { try { if (window != null) { LinkedList currentLayerWindows; if (_layerList.TryGetValue((int) window.uiWindowLayer, out currentLayerWindows) && currentLayerWindows != null && currentLayerWindows.Count > 0) { if (currentLayerWindows.Remove(window)) { } currentLayerWindows.AddLast(window); //DebugUtil.Log($"{window.WindowName} sibling index is {window.transform.GetSiblingIndex()}"); //return; } else { if (currentLayerWindows == null) { currentLayerWindows = new LinkedList(); _layerList.Add((int) window.uiWindowLayer, currentLayerWindows); } currentLayerWindows.AddLast(window); } int siblingIndex = 5; // 让出loading其他想挂在canvas下的奇怪东西 LinkedList layerWindows; for (int i = 0; i <= (int) UIWindowLayer.Max; i++) { if (_layerList.TryGetValue(i, out layerWindows) && layerWindows != null) { if (layerWindows.Count > 0) { var e = layerWindows.GetEnumerator(); while (e.MoveNext()) { var currWindow = e.Current; if (currWindow != null) currWindow.transform?.SetSiblingIndex(siblingIndex++); } } } } var index = window.transform.GetSiblingIndex(); //DebugUtil.Log($"{window.WindowName} sibling index is {index}"); } } catch (Exception e) { DebugUtil.LogError(e); DebugUtil.LogError("{0}.LayerListInsertWindow error, window name = {1}", GetType(), window.name); } } void LayerListRemoveWindow(UIWindow window) { try { if (window != null) { LinkedList currentLayerWindows; if (_layerList.TryGetValue((int)window.uiWindowLayer, out currentLayerWindows)) { currentLayerWindows?.Remove(window); } } } catch (Exception e) { DebugUtil.LogError(e); } } public bool GetTopWindow(out UIWindow window, out UIWindowLayer layer, int banLayerMask) { for (int i = (int)UIWindowLayer.Max; i >= 0; i--) { if (((1 << i) & banLayerMask) == 0) { LinkedList highLayerWindows; if (_layerList.TryGetValue(i, out highLayerWindows)) { if (highLayerWindows.Count > 0) { window = highLayerWindows.Last.Value; if (window != null) { layer = (UIWindowLayer)i; return true; } } } } } window = null; layer = UIWindowLayer.Max; return false; } public int LayerMask(UIWindowLayer layer) { return 1 << ((int)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, ECanvasRoot eCanvasRoot = ECanvasRoot.Static1) { return await _LoadWindow(path, false, eCanvasRoot); } private async UniTask _LoadWindow(string path, bool isActive = false, ECanvasRoot eCanvasRoot = ECanvasRoot.Static1) { 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, eCanvasRoot); _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; } } LayerListInsertWindow(window); if (window == null) { DebugUtil.LogError("Create ui fail: {0}", uipath); return null; } if (!isActive) { 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].CreateWindow(data, wInfo.NotSetMainCamera); } } 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 CloseAllUI(UIWindowCloseType closeType ) { var windowList = mMemoryWindows.ToList(); foreach (var kv in windowList) { var window = kv.Value; window.CloseWindow(closeType); } if (closeType == UIWindowCloseType.HideAndDestroy) { mMemoryWindows.Clear(); _layerList.Clear(); ClearHideStack(); } } public void CloseAllUIExcept(string path) { var windowList = mMemoryWindows.ToList(); foreach (var kv in windowList) { var window = kv.Value; if(window.WindowName != path) { window.CloseWindow(UIWindowCloseType.ForceDestroy); mMemoryWindows.Remove(window.WindowName); var layer=window.uiWindowLayer; _layerList[(int)layer].Remove(window); if(_layerList[(int)layer].Count==0) { _layerList.Remove((int)layer); } } } ClearHideStack(); } #endregion #region ShowAndHide /// /// 和ShowAllUI成都调用 /// /// public void HideAllUI(params string[] exceptions) { var windowList = mMemoryWindows.ToList(); foreach (var kv in windowList) { var window = kv.Value; if (window.uiWindowLayer > UIWindowLayer.Normal) { continue; } if (window.gameObject.activeInHierarchy && !exceptions.Contains(window.WindowName)) { _hideCache.Add(window); window.HideWindow(true); } } } /// /// 和HideAllUI成对调用 /// public void ShowAllUI() { foreach (var v in _hideCache) { var window = v; if (window != null) window.ShowWindow(); } _hideCache.Clear(); } /// /// 展示界面 /// /// /// 展示界面时是否关闭场景主相机 public void Show(string path, bool isMainCameraClose = false) { if (mMemoryWindows.TryGetValue(path, out var window)) { if (!window.gameObject.activeInHierarchy) { window.ShowWindow(); if (isMainCameraClose) { var curCameraActive = CameraManager.Instance.CheckMainCameraIsActive(); if (curCameraActive) { CameraManager.Instance.SetMainCameraActive(false); } } } } } /// /// 隐藏 /// /// /// /// 隐藏界面时是否打开场景主相机 public void Hide(string path, bool isOnlyHide = false, bool isMainCameraActive = false) { if (mMemoryWindows.TryGetValue(path, out var window)) { if (window.gameObject.activeInHierarchy) { window.HideWindow(isOnlyHide); if (isMainCameraActive) { var curCameraActive = CameraManager.Instance.CheckMainCameraIsActive(); if (!curCameraActive) { CameraManager.Instance.SetMainCameraActive(true); } } } } } public async void ShowUITips(string uiName, string content, int showTime = 1500) { //放到最上层 if (!_windowsInfo.ContainsKey(uiName)) { return; } var window = await CreateAndOpenWindow(uiName, content); await UniTask.Delay(showTime); window.CloseWindow(); } 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(UIWindowCloseType.HideAndDestroy); } } public void CloseClickShield(string uiPath) { if (mMemoryWindows.ContainsKey(uiPath)) { var window = mMemoryWindows[uiPath]; window.CloseWindow(UIWindowCloseType.HideAndDestroy); } } private void _OnHideAllUIExcept(params string[] exceptions) { HideAllUI(exceptions); } private void _OnShowAllUIHiden() { ShowAllUI(); } #endregion //根据路径判断UI界面是否打开 public bool IsWindowOpening(string uiPath) { string windowName; if (_openingWindows.TryGetValue(uiPath, out windowName)) { if (windowName != null) { return true; } } return false; } /// /// 关掉所有Normal层已打开的界面,保留传参的界面 /// /// public void CloseAllNormalExcept(string path, bool isShowAnim = true) { var windowsL = _GetLayerWindowList(UIWindowLayer.Normal); if (!mMemoryWindows.ContainsKey(path)) { DebugUtil.LogError("请检查Home返回方法传入UI窗口路径!!!参数:{0}", path); return; } List toBeRemoved = new List(); // UIWindow lastWindow = null; // if (isShowAnim) // { // lastWindow = PopWindow(); // } if (windowsL.Count > 0) { var node = windowsL.First; while (node != null) { var window = node.Value; if (window.WindowName != path) { toBeRemoved.Add(window); } if (node == windowsL.Last) { break; } node = node.Next; } } string[] strL = { path }; ClearHideStack(strL); // if (isShowAnim && lastWindow != null && lastWindow.WindowName != path) // { // lastWindow.CloseWindow(); // } if (toBeRemoved.Count > 0) { for (int i = toBeRemoved.Count - 2; i >= 0; i--) { CloseWindow(toBeRemoved[i].WindowName, UIWindowCloseType.ForceDestroy, -1); } } if (CheckIsWindowInStack(mMemoryWindows[path])) { mMemoryWindows[path].CreateWindow(null, GetIsNotSetCameraByPath(path)); } } public void CloseAllNormalExcept(params string[] paths) { bool isShowAnim = true; var windowsL = _GetLayerWindowList(UIWindowLayer.Normal); foreach (var path in paths) { if (!mMemoryWindows.ContainsKey(path)) { DebugUtil.LogError("请检查Home返回方法传入UI窗口路径!!!参数:{0}", path); return; } } List toBeRemoved = new List(); // UIWindow lastWindow = null; // if (isShowAnim) // { // lastWindow = PopWindow(); // } if (windowsL.Count > 0) { var node = windowsL.First; while (node != null) { var window = node.Value; if (!paths.Contains(window.WindowName)) { toBeRemoved.Add(window); } if (node == windowsL.Last) { break; } node = node.Next; } } //string[] strL = { path }; ClearHideStack(paths); // if (isShowAnim && lastWindow != null && !paths.Contains(lastWindow.WindowName)) // { // lastWindow.CloseWindow(); // } if (toBeRemoved.Count > 0) { for (int i = toBeRemoved.Count - 2; i >= 0; i--) { CloseWindow(toBeRemoved[i].WindowName, UIWindowCloseType.ForceDestroy, -1); } } foreach (var path in paths) { if (CheckIsWindowInStack(mMemoryWindows[path])) { mMemoryWindows[path].CreateWindow(null, GetIsNotSetCameraByPath(path)); } } } public bool CheckWindowIsFullScreen(UIWindow window) { if (_windowsInfo.TryGetValue(window.WindowName, out var windowInfo)) { if (windowInfo.UIOpenType == UIOpenType.FullScreen) { return true; } } return false; } private async void _OnAndroidClickBack() { if (!IsEnableBack) return; if (_uiWindowStack.Count > 0) { var window = _uiWindowStack.Last(); if (await window.OnBack()) { return; } } if (!CheckWindowCreated(UINameConst.UIBackReturn)) { await CreateAndOpenWindow(UINameConst.UIBackReturn); } } public bool CheckWindowLoaded(string uiPath) { if (mMemoryWindows.TryGetValue(uiPath, out var window)) { return true; } return false; } 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); } }