Contents

UI框架2

BasePanelUI面板基类
UIMgrUI管理类
EUiLayerUI层级枚举

UIMgr

using System.Collections.Generic;
using ProjectBase.Res;
using ProjectBase.SingleBase;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

namespace ProjectBase.UI
{
    /// <summary>
    /// UI面板层级枚举
    /// </summary>
    public enum EUiLayer
    {
        Top,
        Mid,
        Bot
    }

    /// <summary>
    /// UI面板管理器
    /// </summary>
    public class UIMgr : Single<UIMgr>
    {
        /// <summary>
        /// Canvas
        /// </summary>
        private RectTransform mCanvas;

        /// <summary>
        /// 顶层
        /// </summary>
        private Transform mTop;

        /// <summary>
        /// 中间层
        /// </summary>
        private Transform mMid;

        /// <summary>
        /// 底层
        /// </summary>
        private Transform mBot;

        /// <summary>
        /// UI路径
        /// </summary>
        private string mPath = "Prefabs/UI/UIPanel/";

        /// <summary>
        /// 面板字典
        /// </summary>
        private Dictionary<string, BasePanel> mPaelDict = new Dictionary<string, BasePanel>();

        /// <summary>
        /// 构造方法
        /// </summary>
        public UIMgr()
        {
            GameObject ui = Object.Instantiate(ResMgr.Instance.Load<GameObject>("Prefabs/UI/UI"));
            Object.DontDestroyOnLoad(ui);
            mCanvas = ui.transform.Find("Canvas").transform as RectTransform;
            mTop = GetCanvas.Find("Top");
            mMid = GetCanvas.Find("Mid");
            mBot = GetCanvas.Find("Bot");
        }

        /// <summary>
        /// 显示面板
        /// </summary>
        /// <param name="name">面板名</param>
        /// <param name="layer">面板层级</param>
        /// <typeparam name="T"></typeparam>
        public void ShowPanel<T>(string name, EUiLayer layer = EUiLayer.Mid)
            where T : BasePanel
        {
            if (mPaelDict.ContainsKey(name))
            {
                mPaelDict[name].transform.SetParent(GetLayer(layer));
                mPaelDict[name].Show();
            }
            else
            {
                //异步加载面板
                ResMgr.Instance.LoadAsync<GameObject>(mPath + name, (obj) =>
                {
                    GameObject panelObj = Object.Instantiate(obj, GetLayer(layer), false);
                    panelObj.name = obj.name; //方便UI面板下的脚本获取name
                    T panel = panelObj.GetComponent<T>();
                    mPaelDict.Add(name, panel);
                    panel.Show();
                });
            }
        }


        /// <summary>
        /// 隐藏面板
        /// </summary>
        /// <param name="name">面板名</param>
        public void HidePanel(string name)
        {
            if (!mPaelDict.ContainsKey(name)) return;
            mPaelDict[name].Hide();
            Object.Destroy(mPaelDict[name].gameObject);
            mPaelDict.Remove(name);
        }

        /// <summary>
        /// 获得Canvas
        /// </summary>
        public RectTransform GetCanvas => mCanvas;

        /// <summary>
        /// 获得面板
        /// 调用ShowPanel显示的面板才能被获取
        /// </summary>
        /// <param name="name">面板名</param>
        /// <returns></returns>
        public BasePanel GetPanel(string name) => mPaelDict.ContainsKey(name) ? mPaelDict[name] : null;


        /// <summary>
        /// 获得层级Transform
        /// </summary>
        /// <param name="layer"></param>
        /// <returns></returns>
        public Transform GetLayer(EUiLayer layer)
        {
            Transform uiLayer = null;
            switch (layer)
            {
                case EUiLayer.Top:
                    uiLayer = mTop;
                    break;
                case EUiLayer.Mid:
                    uiLayer = mMid;
                    break;
                case EUiLayer.Bot:
                    uiLayer = mBot;
                    break;
            }

            return uiLayer;
        }

        /// <summary>
        /// 添加自定义事件
        /// </summary>
        /// <param name="obj">添加事件的物体</param>
        /// <param name="type">事件类型</param>
        /// <param name="callBack">事件回调</param>
        public void AddCustomizeEventListener(GameObject obj, EventTriggerType type,
            UnityAction<BaseEventData> callBack)
        {
            EventTrigger trigger = obj.GetComponent<EventTrigger>();
            if (trigger == null)
            {
                trigger = obj.AddComponent<EventTrigger>();
            }

            foreach (var value in trigger.triggers)
            {
                if (value.eventID != type) continue;
                value.callback.AddListener(callBack);
                return;
            }

            EventTrigger.Entry entry = new EventTrigger.Entry {eventID = type};
            entry.callback.AddListener(callBack);
            trigger.triggers.Add(entry);
        }

        /// <summary>
        /// 删除自定义事件
        /// </summary>
        /// <param name="obj">添加事件的物体</param>
        /// <param name="type">事件类型</param>
        /// <param name="callBack">移除的函数</param>
        public void RemoveCustomizeEventListener(GameObject obj, EventTriggerType type,
            UnityAction<BaseEventData> callBack = null)
        {
            EventTrigger trigger = obj.GetComponent<EventTrigger>();
            if (trigger == null || trigger.triggers.Count == 0) return;
            foreach (var value in trigger.triggers)
            {
                if (value.eventID != type) continue;
                if (callBack == null)
                {
                    value.callback.RemoveAllListeners();
                }
                else
                {
                    value.callback.RemoveListener(callBack);
                }

                break;
            }
        }

        /// <summary>
        /// 屏幕坐标转局部坐标
        /// </summary>
        /// <param name="data"></param>
        /// <param name="transform"></param>
        /// <returns></returns>
        public Vector2 ScreenPointToLocalPoint(PointerEventData data, RectTransform transform)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(transform,
                data.position,
                data.enterEventCamera,
                out var localPos
            );
            return localPos;
        }
    }
}

Baseanel

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

namespace ProjectBase.UI
{
    /// <summary>
    /// UI面板基类
    /// </summary>
    public class BasePanel : MonoBehaviour
    {
        /// <summary>
        /// 组件字典
        /// 存储面板子物体里的组件
        /// </summary>
        private Dictionary<string, List<UIBehaviour>> mControlDict = new Dictionary<string, List<UIBehaviour>>();

        /// <summary>
        /// 从字典获取面板中子物体上的组件
        /// </summary>
        /// <param name="objectName">子物体名字</param>
        /// <typeparam name="T">组件类型</typeparam>
        /// <returns></returns>
        public T GetControl<T>(string objectName) where T : UIBehaviour
        {
            if (mControlDict.ContainsKey(objectName))
            {
                List<UIBehaviour> uiBehaviours = mControlDict[objectName];
                foreach (var t in uiBehaviours)
                {
                    if (t as T)
                    {
                        return t as T;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 获得自身以及子物体上的组件 并存入字典
        /// </summary>
        /// <typeparam name="T">组件类型</typeparam>
        protected void GetChildControl<T>() where T : UIBehaviour
        {
            T[] t = gameObject.GetComponentsInChildren<T>();
            string objectName;
            foreach (var t1 in t)
            {
                objectName = t1.gameObject.name;
                if (!mControlDict.ContainsKey(objectName))
                {
                    mControlDict.Add(objectName, new List<UIBehaviour>());
                }

                mControlDict[objectName].Add(t1);
            }
        }
        
        /// <summary>
        /// 在面板显示
        /// </summary>
        public virtual void Show()
        {
        }

        /// <summary>
        /// 在面板退出
        /// </summary>
        public virtual void Hide()
        {
        }
    }
}

Tips

  • 要把层级物体的锚点设置在屏幕的四角 也就是让层级物体的大小和屏幕相同 否则层级面板下的物体会变形
  • EventTrigger不是ui组件 因为它并不继承自UIBehaviours
  • 不要直接删除EventTrigger.triggers列表中的元素 会报错