UIManager
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace MyMVC
{
public enum UILayerRoot
{
None = 0,
BaseLayer,
PopWindowLayer,
TopLayer,
Count,
}
public class UIManager
{
private static GameObject canvasObj;
private static Camera uiCamera;
private static Canvas canvas;
private static CanvasScaler canvasScaler;
private static GObjectFindTool findTool;
private static Dictionary<UILayerRoot, RectTransform> layerRoots = new Dictionary<UILayerRoot, RectTransform>();
private static Dictionary<Type, UIBase> openUIs = new Dictionary<Type, UIBase>();
private static Dictionary<Type, UIBase> closeUIs = new Dictionary<Type, UIBase>();
private static Dictionary<UILayerRoot, List<UIBase>> openUIsOnLayer = new Dictionary<UILayerRoot, List<UIBase>>();
private static Dictionary<UIBase, UIMediatorBase> uiAndMediators = new Dictionary<UIBase, UIMediatorBase>();
public static void Init()
{
canvasObj = GameObject.Find("Canvas");
if (canvasObj == null)
{
return;
}
UnityEngine.Object.DontDestroyOnLoad(canvasObj);
findTool = GObjectFindTool.Create(canvasObj);
uiCamera = findTool.GetComponent<Camera>("UICamera");
uiCamera.clearFlags = CameraClearFlags.Depth;
canvas = findTool.GetComponent<Canvas>("Canvas");
canvasScaler = findTool.GetComponent<CanvasScaler>("Canvas");
canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
//float sw = canvas.pixelRect.width / canvas.scaleFactor;
//float sh = canvas.pixelRect.height / canvas.scaleFactor;
//if (sw != 0 && sh != 0)
//{
//float f = sw > sh ? sh / sw : sw / sh;
//canvasScaler.matchWidthOrHeight = f;
//}
float o_ratio = canvasScaler.referenceResolution.x / canvasScaler.referenceResolution.y;
float cur_ratio = (float)Screen.width / Screen.height;
canvasScaler.matchWidthOrHeight = cur_ratio < o_ratio ? 0 : 1;
InitUILayerRoots();
}
private static void InitUILayerRoots()
{
AddOnUILayerRoot(UILayerRoot.BaseLayer, findTool.GetComponent<RectTransform>("BaseLayer"), 0);
AddOnUILayerRoot(UILayerRoot.PopWindowLayer, findTool.GetComponent<RectTransform>("PopWindowLayer"), -2000);
AddOnUILayerRoot(UILayerRoot.TopLayer, findTool.GetComponent<RectTransform>("TopLayer"), -4000);
}
private static void AddOnUILayerRoot(UILayerRoot layerType, RectTransform tra, float z)
{
layerRoots[layerType] = tra;
Vector3 pos = tra.anchoredPosition3D;
tra.anchoredPosition3D = new Vector3(pos.x, pos.y, z);
}
public static void OnDestroy()
{
layerRoots.Clear();
openUIs.Clear();
closeUIs.Clear();
openUIsOnLayer.Clear();
uiAndMediators.Clear();
}
public static UIBase Show<TUI, TMediator>(UILayerRoot layer = UILayerRoot.BaseLayer) where TUI : UIBase where TMediator : UIMediatorBase
{
return Show(typeof(TUI), typeof(TMediator), layer);
}
private static UIBase Show(Type uiType, Type mediatorType, UILayerRoot layer)
{
UIBase ui;
if (openUIs.TryGetValue(uiType, out ui))
{
return ui;
}
if (!closeUIs.TryGetValue(uiType, out ui))
{
ui = CreateUI(uiType);
}
ui.gameObject.transform.SetParent(layerRoots[layer], false);
InitUIBase(uiType, ui, mediatorType);
UpdateLayer(layer, ui);
return ui;
}
public static UIBase CreateUI(Type uiType)
{
UIBase ui;
string path = uiType.GetField("ResourcesPath").GetValue(null).ToString();
GameObject prefab = ResourcesMgr.LoadPrefab("UIPrefabs/" + path);
if (prefab == null)
{
Debug.Log("Cannot find " + path);
return null;
}
GameObject go = UnityEngine.Object.Instantiate(prefab);
go.name = path;
ui = go.AddComponent(uiType) as UIBase;
return ui;
}
private static void InitUIBase(Type uiType, UIBase ui, Type mediatorType)
{
openUIs[uiType] = ui;
UIMediatorBase mediator = BindMediator(ui, mediatorType);
ui.gameObject.SetActive(true);
mediator.OnShow();
}
private static UIMediatorBase BindMediator(UIBase ui, Type mediatorType)
{
UIMediatorBase mediator = Activator.CreateInstance(mediatorType, new object[] { ui }) as UIMediatorBase;
uiAndMediators[ui] = mediator;
return mediator;
}
private static void UnBindMediator(UIBase ui)
{
UIMediatorBase mediator;
if (uiAndMediators.TryGetValue(ui, out mediator))
{
MessageManager.UnRegister(mediator);
}
uiAndMediators.Remove(ui);
}
private static void UpdateLayer(UILayerRoot layer, UIBase ui, bool isShow = true)
{
ui.SetUILayerRoot(layer);
if (!openUIsOnLayer.ContainsKey(layer))
{
openUIsOnLayer[layer] = new List<UIBase>();
}
List<UIBase> uis;
if (openUIsOnLayer.TryGetValue(layer, out uis))
{
if (isShow)
{
if (!uis.Contains(ui))
{
uis.Add(ui);
}
else
{
uis.Remove(ui);
uis.Add(ui);
}
}
else
{
uis.Remove(ui);
}
for (int i = 0; i < uis.Count; i++)
{
uis[i].SetSiblingIndex(i);
}
}
}
public static void CloseUI<TUI>() where TUI : UIBase
{
CloseUI(typeof(TUI));
}
private static void CloseUI(Type uiType)
{
UIBase ui;
if (openUIs.TryGetValue(uiType, out ui))
{
openUIs.Remove(uiType);
ui.gameObject.SetActive(false);
UnBindMediator(ui);
closeUIs[uiType] = ui;
UpdateLayer(ui.GetUILayerRoot(), ui, false);
}
}
public static void DestroyAllUI()
{
Debug.LogError("UIManager.DestroyAllUI!");
CloseAllOpenUI();
foreach (var item in closeUIs)
{
UnityEngine.Object.Destroy(item.Value.gameObject);
}
closeUIs.Clear();
openUIsOnLayer.Clear();
}
public static bool IsUIOpen<TUI>() where TUI : UIBase
{
Type uiT = typeof(TUI);
if (openUIs.ContainsKey(uiT))
{
return true;
}
return false;
}
public static void CloseAllOpenUI()
{
List<Type> allOpenUI = new List<Type>(openUIs.Count);
allOpenUI.AddRange(openUIs.Keys);
for (int i = 0; i < allOpenUI.Count; i++)
{
CloseUINow(allOpenUI[i]);
}
}
}
}
UIBase
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.EventSystems;
namespace MyMVC
{
public class UIBase : MonoBehaviour
{
public const string ResourcesPath = "";
private int siblingIndex;
private UILayerRoot uiLayer = UILayerRoot.BaseLayer;
private GObjectFindTool findTool;
protected GObjectFindTool FindTool
{
get
{
if (findTool == null)
{
findTool = GObjectFindTool.Create(gameObject);
}
return findTool;
}
}
protected GameObject GetObj(string objName)
{
return FindTool.GetObject(objName);
}
protected T GetCom<T>(string objName) where T : Component
{
return FindTool.GetComponent<T>(objName);
}
private void OnEnable()
{
StartCoroutine(OnStart());
}
private IEnumerator OnStart()
{
yield return new WaitForEndOfFrame();
OnShow();
}
protected virtual void OnShow() { }
public virtual void InitUI() { }
public void BindButtons(object mediatorObj, List<string> btnNames, string methodPre = "OnClick")
{
Type objType = mediatorObj.GetType();
for (int i = 0; i < btnNames.Count; i++)
{
string btnName = btnNames[i];
GameObject btnObj = FindTool.GetObject(btnName);
if (btnObj == null)
{
Debug.Log("Cannot find " + btnName);
continue;
}
string methodName = methodPre + btnName;
if (objType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) == null)
{
Debug.Log("Cannot find " + methodName);
continue;
}
Action<PointerEventData> func = (Action<PointerEventData>)Delegate.CreateDelegate(typeof(Action<PointerEventData>), mediatorObj, methodName, true, false);
if (func == null)
{
Debug.Log("Cannot CreateDelegate Action<PointerEventData> " + methodName);
continue;
}
UIEvent.Get(btnObj).OnPointerClickCallBack = func;
}
}
public void UnBindButtons()
{
UIEvent[] uIEvents = GetComponentsInChildren<UIEvent>();
for (int i = 0; i < uIEvents.Length; i++)
{
uIEvents[i].OnPointerClickCallBack = null;
}
}
public void SetSiblingIndex(int index)
{
siblingIndex = index;
if (transform.GetSiblingIndex() != siblingIndex)
{
transform.SetSiblingIndex(siblingIndex);
}
}
public void SetUILayerRoot(UILayerRoot layer)
{
uiLayer = layer;
}
public UILayerRoot GetUILayerRoot()
{
return uiLayer;
}
}
}
组件获取工具类 GObjectFindTool
using System.Collections.Generic;
using UnityEngine;
namespace MyMVC
{
public class GObjectFindTool
{
private Dictionary<string, GameObject> objectDic = new Dictionary<string, GameObject>();
public GObjectFindTool(GameObject obj)
{
RegObject(obj);
}
public static GObjectFindTool Create(GameObject obj)
{
return new GObjectFindTool(obj);
}
public void RegObject(GameObject obj)
{
Transform[] trs = obj.GetComponentsInChildren<Transform>(true);
for (int i = 0; i < trs.Length; i++)
{
Transform item = trs[i];
objectDic[item.name.ToLower()] = item.gameObject;
}
string sn = obj.name.ToLower();
if (sn.Contains("(clone)"))
{
sn.Replace("(clone)", "");
}
objectDic[sn] = obj;
}
public static Transform GetObject(GameObject obj, string findName)
{
Transform[] trs = obj.GetComponentsInChildren<Transform>(true);
for (int i = 0; i < trs.Length; i++)
{
Transform item = trs[i];
if (item.name == findName)
{
return item;
}
}
return null;
}
public bool HasObject(string objName)
{
if (string.IsNullOrEmpty(objName))
{
return false;
}
objName = objName.ToLower();
return objectDic.ContainsKey(objName);
}
public GameObject GetObject(string objName)
{
if (string.IsNullOrEmpty(objName))
{
return null;
}
objName = objName.ToLower();
GameObject obj = null;
if (objectDic.TryGetValue(objName, out obj))
{
return obj;
}
return null;
}
public T GetComponent<T>(string objName) where T : Component
{
if (string.IsNullOrEmpty(objName))
{
return null;
}
GameObject cobj = GetObject(objName);
if (cobj == null)
{
return null;
}
return cobj.GetComponent<T>();
}
}
}
加载类 ResourcesMgr
using System.Collections.Generic;
using UnityEngine;
namespace MyMVC
{
public class ResourcesMgr
{
private static Dictionary<string, object> pool = new Dictionary<string, object>();
private static T Load<T>(string path) where T : Object
{
if (pool.ContainsKey(path))
{
return pool[path] as T;
}
T obj = Resources.Load<T>(path);
pool[path] = obj;
return obj;
}
public static T LoadObj<T>(string path) where T : Object
{
return Load<T>(path);
}
public static GameObject LoadPrefab(string path)
{
return Object.Instantiate(Load<GameObject>(path));
}
public static void ClearPool()
{
pool.Clear();
}
}
}
按钮注册相关 UIEvent
using System;
using UnityEngine;
using UnityEngine.EventSystems;
namespace MyMVC
{
public class UIEvent : EventTrigger
{
public static UIEvent Get(GameObject obj)
{
UIEvent e = obj.GetComponent<UIEvent>();
if (e == null)
{
e = obj.AddComponent<UIEvent>();
}
return e;
}
public Action<PointerEventData> OnPointerClickCallBack;
public Action<PointerEventData> OnPointerDownCallBack;
public Action<PointerEventData> OnPointerUpCallBack;
public Action<PointerEventData> OnBeginDragCallBack;
public Action<PointerEventData> OnDragCallBack;
public Action<PointerEventData> OnEndDragCallBack;
public override void OnPointerClick(PointerEventData eventData)
{
if (OnPointerClickCallBack != null)
{
OnPointerClickCallBack(eventData);
}
}
public override void OnPointerDown(PointerEventData eventData)
{
if (OnPointerDownCallBack != null)
{
OnPointerDownCallBack(eventData);
}
}
public override void OnPointerUp(PointerEventData eventData)
{
if (OnPointerUpCallBack != null)
{
OnPointerUpCallBack(eventData);
}
}
public override void OnBeginDrag(PointerEventData eventData)
{
if (OnBeginDragCallBack != null)
{
OnBeginDragCallBack(eventData);
}
}
public override void OnDrag(PointerEventData eventData)
{
if (OnDragCallBack != null)
{
OnDragCallBack(eventData);
}
}
public override void OnEndDrag(PointerEventData eventData)
{
if (OnEndDragCallBack != null)
{
OnEndDragCallBack(eventData);
}
}
}
}
UIMediatorBase
using System.Collections.Generic;
namespace MyMVC
{
public interface IMediator
{
List<string> GetMessageCodes();
void HandleMessage(IMessage msg);
}
public class UIMediatorBase : IMediator
{
public UIMediatorBase(UIBase ui)
{
ui.InitUI();
Register();
}
public virtual void OnShow() { }
public virtual List<string> GetMessageCodes() { return null; }
public virtual void HandleMessage(IMessage msg) { }
private void Register()
{
MessageManager.Register(this);
}
}
}
消息注册相关 MessageManager
using System.Collections.Generic;
namespace MyMVC
{
public class MessageManager
{
private static Dictionary<string, List<IMediator>> CodeMessages = new Dictionary<string, List<IMediator>>();
private static Queue<IMessage> messagesQueue = new Queue<IMessage>();
private static readonly int perFrameMaxMessage = 10;
public static void Register(IMediator mediator)
{
List<string> codes = mediator.GetMessageCodes();
if (codes == null)
{
return;
}
for (int i = 0; i < codes.Count; i++)
{
string code = codes[i];
if (!CodeMessages.ContainsKey(code))
{
CodeMessages[code] = new List<IMediator>();
}
CodeMessages[code].Add(mediator);
}
}
public static void UnRegister(IMediator mediator)
{
foreach (var item in CodeMessages.Values)
{
item.Remove(mediator);
}
}
public static void SendMessage(string codeName, object body = null)
{
if (CodeMessages.ContainsKey(codeName))
{
IMessage msg = new IMessage
{
Code = codeName,
Body = body
};
messagesQueue.Enqueue(msg);
}
}
public static void UpdateMessages()
{
if (messagesQueue.Count > 0)
{
for (int i = 0; i < perFrameMaxMessage; i++)
{
IMessage msg = messagesQueue.Dequeue();
HandleMessage(msg);
if (messagesQueue.Count == 0)
{
break;
}
}
}
}
private static void HandleMessage(IMessage msg)
{
List<IMediator> mediators;
if (CodeMessages.TryGetValue(msg.Code, out mediators))
{
for (int i = 0; i < mediators.Count; i++)
{
mediators[i].HandleMessage(msg);
}
}
}
}
}
消息体 IMessage
namespace MyMVC
{
public class IMessage
{
public string Code = "";
public object Body;
}
}
UIManager 初始化 MessageManager 消息更新 相关 UITestMono
using UnityEngine;
namespace MyMVC
{
public class UITestMono : MonoBehaviour
{
private void Awake()
{
UIManager.Init();
UIManager.Show<Test01UI, Test01UIMediator>();
}
private void Update()
{
MessageManager.UpdateMessages();
}
}
}
消息代码常量定义 MessageConstCodes
namespace MyMVC
{
public class MessageConstCodes
{
public const string TheTestMessageCode = "TheTestMessageCode";
}
}
应用例子说明
using UnityEngine.UI;
namespace MyMVC
{
public class Test01UI : UIBase
{
public new const string ResourcesPath = "Test01UI";
private Text messageText;
public override void InitUI()
{
base.InitUI();
messageText = GetCom<Text>("Text");
}
public void SetText(string msg)
{
messageText.text = msg;
}
}
}
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace MyMVC
{
public class Test01UIMediator : UIMediatorBase
{
private Test01UI ui;
public Test01UIMediator(UIBase ui) : base(ui)
{
this.ui = (Test01UI)ui;
ui.BindButtons(this, new List<string>()
{
"SendBtn",
"Open02UIBtn",
});
}
public override void OnShow()
{
base.OnShow();
Debug.Log("Test01UI show");
}
public override List<string> GetMessageCodes()
{
return new List<string>()
{
MessageConstCodes.TheTestMessageCode,
};
}
public override void HandleMessage(IMessage msg)
{
if (msg.Code.Equals(MessageConstCodes.TheTestMessageCode))
{
ui.SetText(msg.Body.ToString());
}
}
public void OnClickSendBtn(PointerEventData e)
{
MessageManager.SendMessage(MessageConstCodes.TheTestMessageCode, e.clickTime.ToString());
}
public void OnClickOpen02UIBtn(PointerEventData e)
{
UIManager.Show<Test02UI, Test02UIMediator>();
}
}
}