Unity 3D MVC 框架

 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>();
        }
    }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值