using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;// UI界面基类
public abstract class UIBase : MonoBehaviour
{[Header("UI Settings")]public bool keepInStack = true; // 是否保留在界面栈中public bool destroyWhenClose = false; // 关闭时是否销毁// 界面打开关闭事件public UnityEvent onOpen;public UnityEvent onClose;// 界面初始化public virtual void Init() { }// 界面打开// 在UIBase中添加public virtual void Open(){Debug.Log($"Opening {gameObject.name}");gameObject.SetActive(true);onOpen?.Invoke();}public virtual void Close(){Debug.Log($"Closing {gameObject.name}");gameObject.SetActive(false);onClose?.Invoke();if (destroyWhenClose){Debug.Log($"Destroying {gameObject.name}");Destroy(gameObject);}}// 返回按钮处理(Android返回键或界面返回按钮)public virtual void OnBackPressed(){UIManager.Instance.CloseUI(this);}
}// UI管理器
public class UIManager : MonoBehaviour
{private static UIManager _instance;public static UIManager Instance => _instance;[Header("UI Settings")]public Transform uiRoot; // UI根节点public GameObject loadingScreen; // 加载界面private Dictionary<string, GameObject> _uiPrefabs = new Dictionary<string, GameObject>();private Stack<UIBase> _uiStack = new Stack<UIBase>();private Dictionary<string, UIBase> _loadedUIs = new Dictionary<string, UIBase>();private void Awake(){if (_instance != null && _instance != this){Destroy(gameObject);return;}_instance = this;DontDestroyOnLoad(gameObject);}// 注册UI预制体public void RegisterUI(string uiName, GameObject prefab){if (!_uiPrefabs.ContainsKey(uiName)){_uiPrefabs.Add(uiName, prefab);}}// 同步打开UIpublic UIBase OpenUI(string uiName, object data = null){if (loadingScreen != null) loadingScreen.SetActive(true);UIBase ui = GetOrCreateUI(uiName);if (ui == null){Debug.LogError($"UI {uiName} not found!");if (loadingScreen != null) loadingScreen.SetActive(false);return null;}// 强制激活新UIui.gameObject.SetActive(true);// 处理当前UIif (_uiStack.Count > 0){var currentUI = _uiStack.Peek();// 无论keepInStack如何,都关闭当前UIcurrentUI.Close();// 如果新UI不保留栈或当前UI需要销毁if (!ui.keepInStack || currentUI.destroyWhenClose){_uiStack.Pop();if (currentUI.destroyWhenClose){_loadedUIs.Remove(currentUI.gameObject.name);}}}// 初始化并打开新UIui.Init();ui.Open();// 添加到栈(如果需要)if (ui.keepInStack){_uiStack.Push(ui);}if (loadingScreen != null) loadingScreen.SetActive(false);Debug.Log($"当前栈内UI数量: {_uiStack.Count}");return ui;}// 异步打开UIpublic IEnumerator OpenUIAsync(string uiName, object data = null){if (loadingScreen != null) loadingScreen.SetActive(true);yield return null; // 等待一帧UIBase ui = GetOrCreateUI(uiName);if (ui == null){Debug.LogError($"UI {uiName} not found!");if (loadingScreen != null) loadingScreen.SetActive(false);yield break;}if (_uiStack.Count > 0 && !ui.keepInStack){var currentUI = _uiStack.Peek();currentUI.Close();}ui.Init();ui.Open();if (ui.keepInStack){_uiStack.Push(ui);}if (loadingScreen != null) loadingScreen.SetActive(false);}// 关闭UIpublic void CloseUI(UIBase ui){if (ui == null) return;ui.Close();if (_uiStack.Count > 0 && _uiStack.Peek() == ui){_uiStack.Pop();// 打开上一个UIif (_uiStack.Count > 0){var prevUI = _uiStack.Peek();prevUI.Open();}}}// 关闭当前UIpublic void CloseCurrentUI(){if (_uiStack.Count > 0){CloseUI(_uiStack.Peek());}}// 获取或创建UIprivate UIBase GetOrCreateUI(string uiName){// 检查是否已加载if (_loadedUIs.TryGetValue(uiName, out UIBase loadedUI)){return loadedUI;}// 检查是否有预制体if (!_uiPrefabs.TryGetValue(uiName, out GameObject prefab)){Debug.LogError($"UI prefab {uiName} not registered!");return null;}// 实例化UIGameObject uiObj = Instantiate(prefab, uiRoot);UIBase ui = uiObj.GetComponent<UIBase>();if (ui == null){Debug.LogError($"UI {uiName} has no UIBase component!");Destroy(uiObj);return null;}uiObj.name = uiName;_loadedUIs.Add(uiName, ui);return ui;}// 清空所有UIpublic void ClearAll(){while (_uiStack.Count > 0){var ui = _uiStack.Pop();ui.Close();if (ui.destroyWhenClose){_loadedUIs.Remove(ui.gameObject.name);}}}// 处理返回键private void Update(){if (Input.GetKeyDown(KeyCode.Escape)){if (_uiStack.Count > 0){_uiStack.Peek().OnBackPressed();}}}
}
然后注册UI
using UnityEngine;public class GameInitializer : MonoBehaviour
{[SerializeField] private GameObject LoginInterface;[SerializeField] private GameObject SingerOrMulti;[SerializeField] private GameObject ModuleSelect;[SerializeField] private GameObject SandTableSelect;[SerializeField] private GameObject DataReport;[SerializeField] private GameObject SettingInterface;private void Start(){// 注册UI预制体UIManager.Instance.RegisterUI("LoginInterface", LoginInterface);UIManager.Instance.RegisterUI("SingerOrMulti", SingerOrMulti);UIManager.Instance.RegisterUI("ModuleSelect", ModuleSelect);UIManager.Instance.RegisterUI("SandTableSelect", SandTableSelect);UIManager.Instance.RegisterUI("DataReport", DataReport);UIManager.Instance.RegisterUI("SettingInterface", SettingInterface);// 打开主菜单UIManager.Instance.OpenUI("LoginInterface");}
}
调用UI界面 是预制体
脚本要继承UIbase