762 lines
22 KiB
C#
762 lines
22 KiB
C#
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<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 UICanvasLayerManager LayerManager => UICanvasLayerManager.Instance;
|
||
|
||
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();
|
||
|
||
// 初始化层级管理器
|
||
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<string[]>)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<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)
|
||
{
|
||
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
|
||
/// <summary>
|
||
/// 打开一个UI
|
||
/// UIManager.Instance.OpenWindow("Common/GameUI")
|
||
/// </summary>
|
||
|
||
/// <summary>
|
||
/// 创建并打开窗口
|
||
/// </summary>
|
||
/// <param name="path">窗口路径</param>
|
||
/// <param name="data">传递的数据</param>
|
||
/// <param name="overrideStackMode">覆盖栈模式(null则使用配置)。⚠️ 谨慎使用,大部分情况应使用配置</param>
|
||
public async UniTask<UIWindow> CreateAndOpenWindow(string path, object data = null, UIStackMode? overrideStackMode = null)
|
||
{
|
||
DebugUtil.LogP($"打开窗口:{path}");
|
||
if (mMemoryWindows.ContainsKey(path))
|
||
{
|
||
DebugUtil.LogG($"窗口已打开!!!{path}");
|
||
//return null;
|
||
}
|
||
|
||
var window = await _LoadWindow(path, true);
|
||
if (window != null)
|
||
{
|
||
// 初始化和显示窗口
|
||
window.Init(data);
|
||
window.ShowWindow(data);
|
||
|
||
// 获取配置
|
||
var config = GetWindowInfo(path);
|
||
var stackMode = overrideStackMode ?? config.StackMode;
|
||
|
||
// 1. 栈管理
|
||
UINavigationManager.Instance.HandleWindowOpen(window, stackMode);
|
||
|
||
// 2. 可见性管理
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭窗口
|
||
/// </summary>
|
||
/// <param name="wName">窗口名称</param>
|
||
/// <param name="destroy">是否销毁窗口</param>
|
||
public void CloseWindow(string wName, bool destroy)
|
||
{
|
||
var window = GetOpenedWindowByPath<UIWindow>(wName);
|
||
if (window != null)
|
||
{
|
||
window.CloseWindow(destroy);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 打开已加载的窗口(显示并根据配置处理导航栈)
|
||
/// 适用于预加载窗口的显示场景
|
||
/// </summary>
|
||
/// <param name="window">已加载的窗口</param>
|
||
/// <param name="data">传递的数据(可选)</param>
|
||
/// <param name="overrideStackMode">覆盖栈模式(null则使用配置)</param>
|
||
public void OpenLoadedWindow(UIWindow window, object data = null, UIStackMode? overrideStackMode = null)
|
||
{
|
||
if (window == null)
|
||
{
|
||
DebugUtil.LogError("OpenLoadedWindow: window is null");
|
||
return;
|
||
}
|
||
|
||
// 显示窗口
|
||
window.ShowWindow(data);
|
||
|
||
// 获取配置
|
||
var config = GetWindowInfo(window.WindowName);
|
||
var stackMode = overrideStackMode ?? config.StackMode;
|
||
|
||
// 1. 栈管理
|
||
UINavigationManager.Instance.HandleWindowOpen(window, stackMode);
|
||
|
||
// 2. 可见性管理
|
||
UIWindowVisibilityManager.Instance.HandleVisibilityOnOpen(window, config.VisibilityStrategy);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 打开已加载的窗口(通过路径)
|
||
/// </summary>
|
||
public void OpenLoadedWindow(string path, object data = null, UIStackMode? overrideStackMode = null)
|
||
{
|
||
var window = GetOpenedWindowByPath(path);
|
||
if (window != null)
|
||
{
|
||
OpenLoadedWindow(window, data, overrideStackMode);
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.LogError($"OpenLoadedWindow: window not found: {path}");
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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;
|
||
// }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载窗口(不显示)
|
||
/// 用于预加载场景
|
||
/// </summary>
|
||
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, 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 (!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(destroy: true);
|
||
mMemoryWindows.Remove(window.WindowName);
|
||
LayerManager.RemoveWindow(window);
|
||
}
|
||
}
|
||
ClearHideStack();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region ShowAndHide
|
||
|
||
/// <summary>
|
||
/// 隐藏所有UI
|
||
/// 和 ShowAllUI 成对调用
|
||
/// </summary>
|
||
/// <param name="exceptions">不隐藏的UI窗口名称列表</param>
|
||
public void HideAllUI(params string[] exceptions)
|
||
{
|
||
HideAllUI(UICanvasLayer.Max, exceptions);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏指定层级及以下的所有UI
|
||
/// 和 ShowAllUI 成对调用
|
||
/// </summary>
|
||
/// <param name="maxLayer">最大层级(包含该层级及以下的所有UI都会被隐藏)</param>
|
||
/// <param name="exceptions">不隐藏的UI窗口名称列表</param>
|
||
public void HideAllUI(UICanvasLayer maxLayer, params string[] exceptions)
|
||
{
|
||
var hiddenWindows = LayerManager.HideWindowsUpToLayer(maxLayer, exceptions);
|
||
_hideCache.AddRange(hiddenWindows);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏指定层级列表中的所有UI
|
||
/// 和 ShowAllUI 成对调用
|
||
/// </summary>
|
||
/// <param name="layers">要隐藏的层级列表</param>
|
||
/// <param name="exceptions">不隐藏的UI窗口名称列表</param>
|
||
public void HideAllUI(UICanvasLayer[] layers, params string[] exceptions)
|
||
{
|
||
var hiddenWindows = LayerManager.HideWindowsInLayers(layers, exceptions);
|
||
_hideCache.AddRange(hiddenWindows);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 和HideAllUI成对调用
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关掉所有Normal层已打开的界面,保留传参的界面
|
||
/// </summary>
|
||
/// <param name="path"></param>
|
||
public void CloseAllNormalExcept(string path, bool isShowAnim = true)
|
||
{
|
||
var windowsL = LayerManager.GetWindowsInLayer(UICanvasLayer.Normal);
|
||
|
||
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 (window.WindowName != path)
|
||
{
|
||
toBeRemoved.Add(window);
|
||
}
|
||
|
||
if (node == windowsL.Last)
|
||
{
|
||
break;
|
||
}
|
||
|
||
node = node.Next;
|
||
}
|
||
}
|
||
|
||
string[] strL = { path };
|
||
ClearHideStack(strL);
|
||
|
||
if (toBeRemoved.Count > 0)
|
||
{
|
||
for (int i = toBeRemoved.Count - 2; i >= 0; i--)
|
||
{
|
||
toBeRemoved[i].CloseWindow(destroy: true);
|
||
}
|
||
}
|
||
|
||
if (UINavigationManager.Instance.IsWindowInStack(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 = LayerManager.GetWindowsInLayer(UICanvasLayer.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;
|
||
}
|
||
}
|
||
|
||
//string[] strL = { path };
|
||
ClearHideStack(paths);
|
||
|
||
if (toBeRemoved.Count > 0)
|
||
{
|
||
for (int i = toBeRemoved.Count - 2; i >= 0; i--)
|
||
{
|
||
toBeRemoved[i].CloseWindow(destroy: true);
|
||
}
|
||
}
|
||
|
||
foreach (var path in paths)
|
||
{
|
||
if (UINavigationManager.Instance.IsWindowInStack(mMemoryWindows[path]))
|
||
{
|
||
mMemoryWindows[path].ShowWindow();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理除指定UI以外的界面(只包含关闭操作)
|
||
/// </summary>
|
||
/// <param name="paths"></param>
|
||
public void ClearAllNormalExcept(params string[] paths)
|
||
{
|
||
bool isShowAnim = true;
|
||
var windowsL = LayerManager.GetWindowsInLayer(UICanvasLayer.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--)
|
||
{
|
||
toBeRemoved[i].CloseWindow(destroy: true);
|
||
}
|
||
}
|
||
}
|
||
|
||
private async void _OnAndroidClickBack()
|
||
{
|
||
if (!IsEnableBack)
|
||
return;
|
||
|
||
var topWindow = UINavigationManager.Instance.GetTopWindow();
|
||
if (topWindow != null && await topWindow.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);
|
||
}
|
||
|
||
#region Navigation Stack Management
|
||
|
||
/// <summary>
|
||
/// 清空导航栈(保留指定窗口)
|
||
/// </summary>
|
||
public void ClearHideStack(params string[] windowName)
|
||
{
|
||
var stack = UINavigationManager.Instance.NavigationStack;
|
||
|
||
// 倒序遍历,避免索引问题
|
||
for (int i = stack.Count - 1; i >= 0; i--)
|
||
{
|
||
var window = stack[i];
|
||
|
||
// 检查是否是要保留的窗口
|
||
bool shouldKeep = false;
|
||
for (int j = 0; j < windowName.Length; j++)
|
||
{
|
||
if (window.WindowName == windowName[j])
|
||
{
|
||
shouldKeep = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!shouldKeep)
|
||
{
|
||
// 先从导航栈移除,再销毁窗口
|
||
UINavigationManager.Instance.HandleWindowClose(window);
|
||
window.CloseWindow(destroy: true);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空所有导航栈
|
||
/// </summary>
|
||
public void ClearHideStack()
|
||
{
|
||
var stack = UINavigationManager.Instance.NavigationStack;
|
||
|
||
// 先复制列表,避免在遍历时修改集合
|
||
var windowsToClose = new List<UIWindow>(stack);
|
||
UINavigationManager.Instance.Clear();
|
||
|
||
// 再关闭所有窗口
|
||
for (int i = 0; i < windowsToClose.Count; i++)
|
||
{
|
||
windowsToClose[i].CloseWindow(destroy: true);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|