676 lines
20 KiB
C#
676 lines
20 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using Cysharp.Threading.Tasks;
|
||
using Framework;
|
||
using PhxhSDK;
|
||
using UnityEngine;
|
||
|
||
public partial class UIManager : Singlenton<UIManager>, IInitable, IUpdatable
|
||
{
|
||
public const string UI_PREFAB_PATH = "Assets/Art/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;
|
||
/// <summary>
|
||
/// 是否响应返回键
|
||
/// </summary>
|
||
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<string[]>)_OnHideAllUIExcept);
|
||
EventManager.Instance.Register(EventManager.EventName.ShowAllUIHiden, _OnShowAllUIHiden);
|
||
EventManager.Instance.Register(EventManager.EventName.ClearUIStack, (Action<string[]>)ClearHideStack);
|
||
}
|
||
|
||
public void Release()
|
||
{
|
||
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 void Update(float dt)
|
||
{
|
||
foreach (var winKv in mMemoryWindows)
|
||
{
|
||
var window = winKv.Value;
|
||
if (window.IsCreated() && window.gameObject)
|
||
{
|
||
window.Update();
|
||
}
|
||
}
|
||
}
|
||
|
||
#region UIWindow Manager
|
||
|
||
public static void BindWindowObj(UIWindow window, GameObject uiObj)
|
||
{
|
||
window.gameObject = uiObj.gameObject;
|
||
window.transform = uiObj.transform;
|
||
window.rectTransform = uiObj.GetComponent<RectTransform>();
|
||
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)
|
||
{
|
||
var window = await _LoadWindow(path, true);
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
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)
|
||
{
|
||
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<UIWindow>(wName);
|
||
if (window != null)
|
||
{
|
||
window.CloseWindow(closeType, playAnim);
|
||
}
|
||
}
|
||
|
||
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)
|
||
{
|
||
return await _LoadWindow(path, false);
|
||
}
|
||
private async UniTask<UIWindow> _LoadWindow(string path, bool isActive = false)
|
||
{
|
||
|
||
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);
|
||
_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<UIWindow> 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();
|
||
}
|
||
}
|
||
#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(true);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <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, 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;
|
||
}
|
||
|
||
/// <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.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 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;
|
||
}
|
||
}
|
||
|
||
await CreateAndOpenWindow(UINameConst.UIBackReturn);
|
||
}
|
||
|
||
public bool CheckWindowCreated(string uiPath)
|
||
{
|
||
if (mMemoryWindows.TryGetValue(uiPath, out var window))
|
||
{
|
||
return window.IsCreated();
|
||
}
|
||
return false;
|
||
}
|
||
}
|