using System; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; namespace TapSDK.UI { public class UIManager : MonoSingleton { public const int TOPPEST_SORTING_ORDER = 32767; private const int LOADING_PANEL_SORTING_ORDER = TOPPEST_SORTING_ORDER; private const int TOAST_PANEL_SORTING_ORDER = TOPPEST_SORTING_ORDER - 10; private readonly Dictionary _registerPanels = new Dictionary(); // uicamera private Camera _uiCamera; private GameObject _uiRoot; public int uiOpenOrder;// UI打开时的Order值 用来标识界面层级顺序 public Camera UiCamera => _uiCamera; protected override void Init() { if (_uiRoot == null) { CreateUIRoot(); } } private void CreateUIRoot() { _uiRoot = Instantiate(Resources.Load("TapSDKUIRoot")); DontDestroyOnLoad(_uiRoot); var canvas = _uiRoot.GetComponent(); _uiCamera = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? Camera.main : canvas.worldCamera; } /// /// Get Or Create UI asynchronously /// /// the prefab path /// opening param /// if u want to get ui do something,here is for u, which is invoked after BasePanelController.OnLoadSuccess /// /// get panel instance if sync mode load public async Task OpenUIAsync(string path, IOpenPanelParameter param = null, Action onAsyncGet = null) where TPanelController : BasePanelController { var basePanelController = GetUI(); // 如果已有界面(之前缓存过的),则不执行任何操作 if (basePanelController != null) { if (!basePanelController.canvas.enabled) { basePanelController.canvas.enabled = true; } onAsyncGet?.Invoke(basePanelController); return basePanelController; } ResourceRequest request = Resources.LoadAsync(path); while (request.isDone == false) { await Task.Yield(); } GameObject go = request.asset as GameObject; var basePanel = Instantiate(go).GetComponent(); if (basePanel != null) { InternalOnPanelLoaded(typeof(TPanelController), basePanel, param); onAsyncGet?.Invoke(basePanel); return basePanel; } else { return null; } } /// /// Get Or Create UI asynchronously /// /// the panel Type /// the prefab path /// opening param /// if u want to get ui do something,here is for u, which is invoked after BasePanelController.OnLoadSuccess /// get panel instance if sync mode load public async Task OpenUIAsync(Type panelType, string path, IOpenPanelParameter param = null, Action onAsyncGet = null) { if (!typeof(BasePanelController).IsAssignableFrom(panelType)) { return null; } var basePanelController = GetUI(panelType); // 如果已有界面(之前缓存过的),则不执行任何操作 if (basePanelController != null) { if (!basePanelController.canvas.enabled) { basePanelController.canvas.enabled = true; } onAsyncGet?.Invoke(basePanelController); return basePanelController; } ResourceRequest request = Resources.LoadAsync(path); while (request.isDone == false) { await Task.Yield(); } GameObject go = request.asset as GameObject; var basePanel = Instantiate(go).GetComponent(); if (basePanel != null) { InternalOnPanelLoaded(panelType, basePanel, param); onAsyncGet?.Invoke(basePanel); return basePanel; } else { return null; } } /// /// Get Or Create UI /// /// the prefab path /// opening param /// /// get panel instance if sync mode load public TPanelController OpenUI(string path, IOpenPanelParameter param = null) where TPanelController : BasePanelController { TPanelController basePanelController = GetUI(); // 如果已有界面(之前缓存过的),则不执行任何操作 if (basePanelController != null) { if (!basePanelController.canvas.enabled) { basePanelController.canvas.enabled = true; } return basePanelController; } var go = Resources.Load(path) as GameObject; if (go != null) { var basePanel = GameObject.Instantiate(go).GetComponent(); uiOpenOrder++; _registerPanels.Add(typeof(TPanelController), basePanel); basePanel.OnLoaded(param); basePanel.SetOpenOrder(uiOpenOrder); return basePanel; } return null; } /// /// Get Or Create UI /// /// panel type MUST based on BasePanelController /// the prefab path /// opening param /// get panel instance if sync mode load public BasePanelController OpenUI(Type panelType, string path, IOpenPanelParameter param = null) { if (!typeof(BasePanelController).IsAssignableFrom(panelType)) { return null; } var basePanelController = GetUI(panelType); // 如果已有界面(之前缓存过的),则不执行任何操作 if (basePanelController != null) { if (basePanelController != null && !basePanelController.canvas.enabled) { basePanelController.canvas.enabled = true; } return basePanelController; } var panelGo = Resources.Load(path) as GameObject; if (panelGo != null) { var basePanel = GameObject.Instantiate(panelGo).GetComponent(); uiOpenOrder++; _registerPanels.Add(panelType, basePanel); basePanel.OnLoaded(param); basePanel.SetOpenOrder(uiOpenOrder); return basePanel; } return null; } public BasePanelController GetUI(Type panelType) { if (!typeof(BasePanelController).IsAssignableFrom(panelType)) { return null; } if (_registerPanels.TryGetValue(panelType, out BasePanelController basePanelController)) { return basePanelController; } return null; } public TPanelController GetUI() where TPanelController : BasePanelController { Type panelType = typeof(TPanelController); if (_registerPanels.TryGetValue(panelType, out BasePanelController panel)) { return (TPanelController)panel; } return null; } public bool CloseUI(Type panelType) { if (!typeof(BasePanelController).IsAssignableFrom(panelType)) { return false; } BasePanelController baseController = GetUI(panelType); if (baseController != null) { if (panelType == typeof(BasePanelController)) // 标尺界面是测试界面 不用关闭 return false; else baseController.Close(); return true; } return false; } public bool CloseUI() where TPanelController : BasePanelController { TPanelController panel = GetUI(); if (panel != null) { panel.Close(); return true; } return false; } /// /// add ui would invoked after create ui automatically, don't need mannually call it in most case /// public void AddUI(BasePanelController panel) { if (panel == null) { return; } panel.transform.SetParent(panel.AttachedParent); panel.transform.localPosition = Vector3.zero; panel.transform.localScale = Vector3.one; panel.transform.localRotation = Quaternion.identity; panel.gameObject.name = panel.gameObject.name.Replace("(Clone)", ""); } /// /// remove ui would invoked automatically, don't need mannually call it in most case /// public void RemoveUI(BasePanelController panel) { if (panel == null) { return; } Type panelType = panel.GetType(); if (_registerPanels.ContainsKey(panelType)) { _registerPanels.Remove(panelType); } panel.Dispose(); } /// /// take some ui to the most top layer /// /// public void ToppedUI(Type panelType) { if (!typeof(BasePanelController).IsAssignableFrom(panelType)) { return; } ToppedUI(GetUI(panelType)); } /// /// take some ui to the most top layer /// /// public void ToppedUI(BasePanelController panel) { if (panel == null) { return; } uiOpenOrder++; panel.SetOpenOrder(uiOpenOrder); } /// /// open toast panel for tip info /// public void OpenToast(string text, float popupTime = 2.0f) { if (!string.IsNullOrEmpty(text) && popupTime > 0) { var toast = OpenUI("Toast", new ToastPanelOpenParam(text, popupTime)); if (toast != null) { var rect = toast.transform as RectTransform; rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.anchoredPosition = Vector2.zero; rect.sizeDelta = Vector2.zero; toast.SetOpenOrder(TOAST_PANEL_SORTING_ORDER); } } } /// /// open toast panel for tip info /// public async Task OpenToastAsync(string text, float popupTime = 2.0f) { if (!string.IsNullOrEmpty(text) && popupTime > 0) { var toast = await OpenUIAsync("Toast", new ToastPanelOpenParam(text, popupTime)); if (toast != null) { var rect = toast.transform as RectTransform; rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.anchoredPosition = Vector2.zero; rect.sizeDelta = Vector2.zero; toast.SetOpenOrder(TOAST_PANEL_SORTING_ORDER); } } } /// /// open loading panel that would at the toppest layer and block interaction /// public void OpenLoading() { var loadingPanel = OpenUI("Loading"); if (loadingPanel != null) { var rect = loadingPanel.transform as RectTransform; rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.anchoredPosition = Vector2.zero; rect.sizeDelta = Vector2.zero; // https://www.reddit.com/r/Unity3D/comments/2b1g1l/order_in_layer_maximum_value/ loadingPanel.SetOpenOrder(LOADING_PANEL_SORTING_ORDER); } } /// /// open loading panel that would at the toppest layer and block interaction /// public async Task OpenLoadingAsync() { var loadingPanel = await OpenUIAsync("Loading"); if (loadingPanel != null) { var rect = loadingPanel.transform as RectTransform; rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.anchoredPosition = Vector2.zero; rect.sizeDelta = Vector2.zero; // https://www.reddit.com/r/Unity3D/comments/2b1g1l/order_in_layer_maximum_value/ loadingPanel.SetOpenOrder(LOADING_PANEL_SORTING_ORDER); } } public void CloseLoading() { var loadingPanel = GetUI(); if (loadingPanel != null) { loadingPanel.Close(); } } private void InternalOnPanelLoaded(Type tPanelController, BasePanelController basePanel, IOpenPanelParameter param = null) { uiOpenOrder++; _registerPanels.Add(tPanelController, basePanel); basePanel.OnLoaded(param); basePanel.SetOpenOrder(uiOpenOrder); } #region external api public Transform GetUIRootTransform() { return _uiRoot.transform; } public Camera GetUICamera() { return _uiCamera; } #endregion } }