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

918 lines
27 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;
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<UIManager>, IInitable, IUpdatable
{
public const string UI_PREFAB_PATH = "Assets/Art_Out/UI/Prefab/{0}.prefab";
public Dictionary<string, UIWindow> mMemoryWindows = new Dictionary<string, UIWindow>();
private Dictionary<int, LinkedList<UIWindow>> _layerList = new Dictionary<int, LinkedList<UIWindow>>(16);
private ScreenOrientation _currentOrientation;
private Dictionary<string, string> _openingWindows = new Dictionary<string, string>();
private List<UIWindow> _hideCache = new List<UIWindow>();
private UIWindow _curFullScreen;
private Dictionary<GameObject, UIWindow> _uiWindowObjDic = new Dictionary<GameObject, UIWindow>();
public Dictionary<GameObject, UIWindow> UIWindowObjDic => _uiWindowObjDic;
public Vector2 Size;
/// <summary>
/// UI和主相机屏幕缩放
/// </summary>
public Vector2 UIAndMainScreenScale;
/// <summary>
/// UI和UI屏幕缩放
/// </summary>
public Vector2 UIAndUIScreenScale;
/// <summary>
/// 禁用返回键计数
/// </summary>
private int disableBackCount;
/// <summary>
/// 是否响应返回键
/// </summary>
public bool IsEnableBack
{
get { return disableBackCount <= 0; }
set
{
if (value)
{
if (disableBackCount > 0)
--disableBackCount;
}
else
++disableBackCount;
}
}
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<string[]>)_OnHideAllUIExcept);
EventManager.Instance.Register(EventManager.EventName.ShowAllUIHiden, _OnShowAllUIHiden);
EventManager.Instance.Register(EventManager.EventName.ClearUIStack, (Action<string[]>)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<string[]>)_OnHideAllUIExcept);
EventManager.Instance.Unregister(EventManager.EventName.ShowAllUIHiden, _OnShowAllUIHiden);
EventManager.Instance.Unregister(EventManager.EventName.ClearUIStack, (Action<string[]>)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)
{
window.Update(dt);
}
}
}
}
_UpdateInputBlockTimer(dt);
}
#region UIWindow Manager
public static void BindWindowObj(UIWindow window, GameObject uiObj)
{
window.gameObject = uiObj.gameObject;
window.transform = uiObj.transform;
window.name = uiObj.name;
}
#endregion
#region OpenWindowAPI
/// <summary>
/// 打开一个UI
/// UIManager.Instance.OpenWindow("Common/GameUI")
/// </summary>
//重载一下传参的Open
public async UniTask<UIWindow> 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.HideWindow();
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.Init(data);
window.ShowWindow(data);
if (window.uiWindowLayer == UIWindowLayer.Normal)
{
PushWindow(window);
}
}
return window;
}
//先打开后关闭
// public async UniTask<UIWindow> 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)
{
var window = GetOpenedWindowByPath<UIWindow>(wName);
if (window != null)
{
window.CloseWindow(closeType);
}
}
public void HideWindow(string wName)
{
var window = GetOpenedWindowByPath<UIWindow>(wName);
if (window != null)
{
window.HideWindow();
}
}
public T GetOpenedWindowByPath<T>(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<UIWindow> 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<UIWindow>();
_layerList.Add((int) window.uiWindowLayer, currentLayerWindows);
}
currentLayerWindows.AddLast(window);
}
int siblingIndex = 5; // 让出loading其他想挂在canvas下的奇怪东西
LinkedList<UIWindow> 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<UIWindow> 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<UIWindow> 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<UIWindow> LoadWindow(string path, ECanvasRoot eCanvasRoot = ECanvasRoot.Static1)
{
return await _LoadWindow(path, false, eCanvasRoot);
}
private async UniTask<UIWindow> _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].Init(data);
mMemoryWindows[uiName].ShowWindow(data);
}
}
public void ForeachUI(Action<UIWindow> 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(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
/// <summary>
/// 和ShowAllUI成都调用
/// </summary>
/// <param name="exceptions"></param>
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();
}
}
}
/// <summary>
/// 和HideAllUI成对调用
/// </summary>
public void ShowAllUI()
{
foreach (var v in _hideCache)
{
var window = v;
if (window != null)
window.ShowWindow();
}
_hideCache.Clear();
}
/// <summary>
/// 展示界面
/// </summary>
/// <param name="path"></param>
/// <param name="isMainCameraClose"></param> 展示界面时是否关闭场景主相机
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);
}
}
}
}
}
/// <summary>
/// 隐藏
/// </summary>
/// <param name="path"></param>
/// <param name="isOnlyHide"></param>
/// <param name="isMainCameraActive"></param> 隐藏界面时是否打开场景主相机
public void Hide(string path)
{
if (mMemoryWindows.TryGetValue(path, out var window))
{
if (window.gameObject.activeInHierarchy)
{
window.HideWindow();
}
}
}
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;
}
/// <summary>
/// 关掉所有Normal层已打开的界面保留传参的界面
/// </summary>
/// <param name="path"></param>
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<UIWindow> toBeRemoved = new List<UIWindow>();
// 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(UIWindowCloseType.HideAndDestroy);
// }
if (toBeRemoved.Count > 0)
{
for (int i = toBeRemoved.Count - 2; i >= 0; i--)
{
CloseWindow(toBeRemoved[i].WindowName, UIWindowCloseType.ForceDestroy);
}
}
if (CheckIsWindowInStack(mMemoryWindows[path]))
{
mMemoryWindows[path].ShowWindow();
}
}
/// <summary>
/// 打开指定界面,并关闭其他界面
/// </summary>
/// <param name="paths"></param>
/// <remarks>如果只需要关闭界面请使用ClearAllNormalExcept方法</remarks>
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<UIWindow> toBeRemoved = new List<UIWindow>();
// 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(UIWindowCloseType.HideAndDestroy);
// }
if (toBeRemoved.Count > 0)
{
for (int i = toBeRemoved.Count - 2; i >= 0; i--)
{
CloseWindow(toBeRemoved[i].WindowName, UIWindowCloseType.ForceDestroy);
}
}
foreach (var path in paths)
{
if (CheckIsWindowInStack(mMemoryWindows[path]))
{
mMemoryWindows[path].ShowWindow();
}
}
}
/// <summary>
/// 清理除指定UI以外的界面(只包含关闭操作)
/// </summary>
/// <param name="paths"></param>
public void ClearAllNormalExcept(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<UIWindow> toBeRemoved = new List<UIWindow>();
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;
}
}
ClearHideStack(paths);
if (toBeRemoved.Count > 0)
{
for (int i = toBeRemoved.Count - 2; i >= 0; i--)
{
CloseWindow(toBeRemoved[i].WindowName, UIWindowCloseType.ForceDestroy);
}
}
}
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 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<RectTransform>();
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);
}
}