UI管理模块——UI基类
帮助面板通过代码快速找到各类子控件
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;/// <summary>/// 面板基类/// 找到所有自己面板下的控件对象/// 他应该提供显示或隐藏的行为/// </summary>public class BasePanel : MonoBehaviour{// 通过里氏转换原则, 来存储所有的控件private Dictionary<string, List<UIBehaviour>> controlDic = new Dictionary<string, List<UIBehaviour>>();void Awake(){FindChildrenControl<Button>();FindChildrenControl<Image>();FindChildrenControl<Text>();FindChildrenControl<Toggle>();FindChildrenControl<Slider>();FindChildrenControl<ScrollRect>();}/// <summary>/// 显示自己/// </summary>public virtual void ShowMe(){}/// <summary>/// 隐藏自己/// </summary>public virtual void HideMe(){}/// <summary>/// 找到子对象的对应控件/// </summary>/// <typeparam name="T"></typeparam>private void FindChildrenControl<T>() where T : UIBehaviour{T[] controls = this.GetComponentsInChildren<T>();string objName;for (int i = 0; i < controls.Length; i++){objName = controls[i].gameObject.name;if (controlDic.ContainsKey(objName)){controlDic[objName].Add(controls[i]);}else{controlDic.Add(objName, new List<UIBehaviour>() { controls[i] });}}}/// <summary>/// 得到对应名字的脚本/// </summary>/// <typeparam name="T"></typeparam>/// <param name="controlName"></param>/// <returns></returns>protected T GetControl<T>(string controlName) where T : UIBehaviour{if (controlDic.ContainsKey(controlName)){for (int i = 0; i < controlDic[controlName].Count; ++i){if (controlDic[controlName][i] is T){return controlDic[controlName][i] as T;}}}return null;}}
UI管理模块——UI管理器
管理所有显示的面板,提供给其他游戏系统接口,用来显示面板和隐藏面板
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.Events;/// <summary>/// UI层级枚举/// </summary>public enum E_UI_Layer{Bot,Mid,Top,System}public class UIManager : BaseManager<UIManager>{public Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();//private Transform canvas;// 为UI分层private Transform bot; // 底层private Transform mid; // 中层private Transform top; // 顶层private Transform system; // 系统层// 记录UI的Canvas父对象 方便以后外部可能会使用他public RectTransform canvas;public UIManager(){// 创建Canvas, 让其过场景不移除GameObject obj = ResMgr.GetInstance().Load<GameObject>("UI/Canvas");canvas = obj.transform as RectTransform;GameObject.DontDestroyOnLoad(obj);// 找到各层bot = canvas.Find("Bot");mid = canvas.Find("Mid");top = canvas.Find("Top");system = canvas.Find("System");// 创建EventSystemobj = ResMgr.GetInstance().Load<GameObject>("UI/EventSystem");GameObject.DontDestroyOnLoad(obj);}/// <summary>/// 显示面板/// </summary>/// <typeparam name="T">面板脚本类型</typeparam>/// <param name="panelName">面板名</param>/// <param name="layer">显示在哪一层</param>/// <param name="callBack">当面板预设体创建成功后, 想要做的事</param>public void ShowPanel<T>(string panelName, E_UI_Layer layer = E_UI_Layer.Mid, UnityAction<T> callBack = null) where T : BasePanel{// 面板已经存在if (panelDic.ContainsKey(panelName)){panelDic[panelName].ShowMe();if (callBack != null){callBack(panelDic[panelName] as T);}//// 避免面板重复加载, 如果存在该面板则直接显示, 调用回调函数后, 直接Return, 不再处理后面的异步加载return;}// 异步加载面板ResMgr.GetInstance().LoadAsync<GameObject>("UI/" + panelName, (obj) =>{// 把他作为Canvas的子对象, 并且要设置他的相对位置// 找到父对象 , 显示在哪一层Transform father = bot;switch (layer){case E_UI_Layer.Mid:father = mid;break;case E_UI_Layer.Top:father = top;break;case E_UI_Layer.System:father = system;break;}// 设置父对象, 相对位置和大小obj.transform.SetParent(father,false);obj.transform.localPosition = Vector3.zero;obj.transform.localScale = Vector3.one;(obj.transform as RectTransform).offsetMax = Vector2.zero;(obj.transform as RectTransform).offsetMin = Vector2.zero;// 得到预设体上的的面板脚本T panel = obj.GetComponent<T>();// 处理面板创建完成后的逻辑 (因为是异步加载面板, 要做延时处理, 只有当面板真正加载完时, 才会做外面想要做的事情.)if (callBack != null){callBack(panel);}panelDic[panelName].ShowMe();// 把面板存起来panelDic.Add(panelName, panel);});}/// <summary>/// 隐藏面板/// </summary>/// <param name="panelName">面板名</param>public void HidePanel(string panelName){if (panelDic.ContainsKey(panelName)){panelDic[panelName].HideMe();GameObject.Destroy(panelDic[panelName].gameObject);panelDic.Remove(panelName);}}/// <summary>/// 得到某一个已经显示的面板/// </summary>/// <param name="panelName">面板名</param>public T GetPanel<T>(string panelName)where T:BasePanel{if(panelDic.ContainsKey(panelName)){return panelDic[panelName] as T;}return null;}}
使用

using System.Collections;using System.Collections.Generic;using UnityEngine;public class UITest : MonoBehaviour{void Start(){UIManager.GetInstance().ShowPanel<LoginPanel>("LoginPanel", E_UI_Layer.Bot, showPanelOver);}private void showPanelOver(LoginPanel panel){panel.IninInfo();Invoke("DelayHide", 1);}private void DelayHide(){UIManager.GetInstance().HidePanel("LoginPanel");}}
UI管理模块——优化面板基类事件监听
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;/// <summary>/// 面板基类/// 帮助我门通过代码快速的找到所有的子控件/// 方便我们在子类中处理逻辑/// 节约找控件的工作量/// </summary>public class BasePanel : MonoBehaviour{//通过里式转换原则 来存储所有的控件private Dictionary<string, List<UIBehaviour>> controlDic = new Dictionary<string, List<UIBehaviour>>();// Use this for initializationprotected virtual void Awake () {FindChildrenControl<Button>();FindChildrenControl<Image>();FindChildrenControl<Text>();FindChildrenControl<Toggle>();FindChildrenControl<Slider>();FindChildrenControl<ScrollRect>();FindChildrenControl<InputField>();}/// <summary>/// 显示自己/// </summary>public virtual void ShowMe(){}/// <summary>/// 隐藏自己/// </summary>public virtual void HideMe(){}protected virtual void OnClick(string btnName){}protected virtual void OnValueChanged(string toggleName, bool value){}/// <summary>/// 得到对应名字的对应控件脚本/// </summary>/// <typeparam name="T"></typeparam>/// <param name="controlName"></param>/// <returns></returns>protected T GetControl<T>(string controlName) where T : UIBehaviour{if(controlDic.ContainsKey(controlName)){for( int i = 0; i <controlDic[controlName].Count; ++i ){if (controlDic[controlName][i] is T)return controlDic[controlName][i] as T;}}return null;}/// <summary>/// 找到子对象的对应控件/// </summary>/// <typeparam name="T"></typeparam>private void FindChildrenControl<T>() where T:UIBehaviour{T[] controls = this.GetComponentsInChildren<T>();for (int i = 0; i < controls.Length; ++i){string objName = controls[i].gameObject.name;if (controlDic.ContainsKey(objName))controlDic[objName].Add(controls[i]);elsecontrolDic.Add(objName, new List<UIBehaviour>() { controls[i] });//如果是按钮控件if(controls[i] is Button){(controls[i] as Button).onClick.AddListener(()=>{OnClick(objName);});}//如果是单选框或者多选框else if(controls[i] is Toggle){(controls[i] as Toggle).onValueChanged.AddListener((value) =>{OnValueChanged(objName, value);});}}}}
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.Events;/// <summary>/// UI层级/// </summary>public enum E_UI_Layer{Bot,Mid,Top,System,}/// <summary>/// UI管理器/// 1.管理所有显示的面板/// 2.提供给外部 显示和隐藏等等接口/// </summary>public class UIManager : BaseManager<UIManager>{public Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();private Transform bot;private Transform mid;private Transform top;private Transform system;//记录我们UI的Canvas父对象 方便以后外部可能会使用它public RectTransform canvas;public UIManager(){//创建Canvas 让其过场景的时候 不被移除GameObject obj = ResMgr.GetInstance().Load<GameObject>("UI/Canvas");canvas = obj.transform as RectTransform;GameObject.DontDestroyOnLoad(obj);//找到各层bot = canvas.Find("Bot");mid = canvas.Find("Mid");top = canvas.Find("Top");system = canvas.Find("System");//创建EventSystem 让其过场景的时候 不被移除obj = ResMgr.GetInstance().Load<GameObject>("UI/EventSystem");GameObject.DontDestroyOnLoad(obj);}/// <summary>/// 通过层级枚举 得到对应层级的父对象/// </summary>/// <param name="layer"></param>/// <returns></returns>public Transform GetLayerFather(E_UI_Layer layer){switch(layer){case E_UI_Layer.Bot:return this.bot;case E_UI_Layer.Mid:return this.mid;case E_UI_Layer.Top:return this.top;case E_UI_Layer.System:return this.system;}return null;}/// <summary>/// 显示面板/// </summary>/// <typeparam name="T">面板脚本类型</typeparam>/// <param name="panelName">面板名</param>/// <param name="layer">显示在哪一层</param>/// <param name="callBack">当面板预设体创建成功后 你想做的事</param>public void ShowPanel<T>(string panelName, E_UI_Layer layer = E_UI_Layer.Mid, UnityAction<T> callBack = null) where T:BasePanel{if (panelDic.ContainsKey(panelName)){panelDic[panelName].ShowMe();// 处理面板创建完成后的逻辑if (callBack != null)callBack(panelDic[panelName] as T);//避免面板重复加载 如果存在该面板 即直接显示 调用回调函数后 直接return 不再处理后面的异步加载逻辑return;}ResMgr.GetInstance().LoadAsync<GameObject>("UI/" + panelName, (obj) =>{//把他作为 Canvas的子对象//并且 要设置它的相对位置//找到父对象 你到底显示在哪一层Transform father = bot;switch(layer){case E_UI_Layer.Mid:father = mid;break;case E_UI_Layer.Top:father = top;break;case E_UI_Layer.System:father = system;break;}//设置父对象 设置相对位置和大小obj.transform.SetParent(father);obj.transform.localPosition = Vector3.zero;obj.transform.localScale = Vector3.one;(obj.transform as RectTransform).offsetMax = Vector2.zero;(obj.transform as RectTransform).offsetMin = Vector2.zero;//得到预设体身上的面板脚本T panel = obj.GetComponent<T>();// 处理面板创建完成后的逻辑if (callBack != null)callBack(panel);panel.ShowMe();//把面板存起来panelDic.Add(panelName, panel);});}/// <summary>/// 隐藏面板/// </summary>/// <param name="panelName"></param>public void HidePanel(string panelName){if(panelDic.ContainsKey(panelName)){panelDic[panelName].HideMe();GameObject.Destroy(panelDic[panelName].gameObject);panelDic.Remove(panelName);}}/// <summary>/// 得到某一个已经显示的面板 方便外部使用/// </summary>public T GetPanel<T>(string name) where T:BasePanel{if (panelDic.ContainsKey(name))return panelDic[name] as T;return null;}}
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;public class LoginPanel : BasePanel {//public Button btnStart;//public Button btnQuit;protected override void Awake(){//一定不能少 因为需要执行父类的awake来初始化一些信息 比如找控件 加事件监听base.Awake();//在下面处理自己的一些初始化逻辑}// Use this for initializationvoid Start () {//GetControl<Button>("btnStart").onClick.AddListener(ClickStart);//GetControl<Button>("btnQuit").onClick.AddListener(ClickQuit);UIManager.AddCustomEventListener(GetControl<Button>("btnStart"), EventTriggerType.PointerEnter, (data)=>{Debug.Log("进入");});UIManager.AddCustomEventListener(GetControl<Button>("btnStart"), EventTriggerType.PointerExit, (data) => {Debug.Log("离开");});}private void Drag(BaseEventData data){}private void PointerDown(BaseEventData data){}// Update is called once per framevoid Update () {}public override void ShowMe(){base.ShowMe();//显示面板时 想要执行的逻辑 这个函数 在UI管理器中 会自动帮我们调用//只要重写了它 就会执行里面的逻辑}protected override void OnClick(string btnName){switch(btnName){case "btnStart":Debug.Log("btnStart被点击");break;case "btnQuit":Debug.Log("btnQuit被点击");break;}}protected override void OnValueChanged(string toggleName, bool value){//在这来根据名字判断 到底是那一个单选框或者多选框状态变化了 当前状态就是传入的value}public void InitInfo(){Debug.Log("初始化数据");}//点击开始按钮的处理public void ClickStart(){}//点击开始按钮的处理public void ClickQuit(){Debug.Log("S");}}
UI管理模块——自定义事件监听
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.Events;using UnityEngine.EventSystems;/// <summary>/// UI层级/// </summary>public enum E_UI_Layer{Bot,Mid,Top,System,}/// <summary>/// UI管理器/// 1.管理所有显示的面板/// 2.提供给外部 显示和隐藏等等接口/// </summary>public class UIManager : BaseManager<UIManager>{public Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();private Transform bot;private Transform mid;private Transform top;private Transform system;//记录我们UI的Canvas父对象 方便以后外部可能会使用它public RectTransform canvas;public UIManager(){//创建Canvas 让其过场景的时候 不被移除GameObject obj = ResMgr.GetInstance().Load<GameObject>("UI/Canvas");canvas = obj.transform as RectTransform;GameObject.DontDestroyOnLoad(obj);//找到各层bot = canvas.Find("Bot");mid = canvas.Find("Mid");top = canvas.Find("Top");system = canvas.Find("System");//创建EventSystem 让其过场景的时候 不被移除obj = ResMgr.GetInstance().Load<GameObject>("UI/EventSystem");GameObject.DontDestroyOnLoad(obj);}/// <summary>/// 通过层级枚举 得到对应层级的父对象/// </summary>/// <param name="layer"></param>/// <returns></returns>public Transform GetLayerFather(E_UI_Layer layer){switch (layer){case E_UI_Layer.Bot:return this.bot;case E_UI_Layer.Mid:return this.mid;case E_UI_Layer.Top:return this.top;case E_UI_Layer.System:return this.system;}return null;}/// <summary>/// 显示面板/// </summary>/// <typeparam name="T">面板脚本类型</typeparam>/// <param name="panelName">面板名</param>/// <param name="layer">显示在哪一层</param>/// <param name="callBack">当面板预设体创建成功后 你想做的事</param>public void ShowPanel<T>(string panelName, E_UI_Layer layer = E_UI_Layer.Mid, UnityAction<T> callBack = null) where T : BasePanel{if (panelDic.ContainsKey(panelName)){panelDic[panelName].ShowMe();// 处理面板创建完成后的逻辑if (callBack != null)callBack(panelDic[panelName] as T);//避免面板重复加载 如果存在该面板 即直接显示 调用回调函数后 直接return 不再处理后面的异步加载逻辑return;}ResMgr.GetInstance().LoadAsync<GameObject>("UI/" + panelName, (obj) =>{//把他作为 Canvas的子对象//并且 要设置它的相对位置//找到父对象 你到底显示在哪一层Transform father = bot;switch (layer){case E_UI_Layer.Mid:father = mid;break;case E_UI_Layer.Top:father = top;break;case E_UI_Layer.System:father = system;break;}//设置父对象 设置相对位置和大小obj.transform.SetParent(father);obj.transform.localPosition = Vector3.zero;obj.transform.localScale = Vector3.one;(obj.transform as RectTransform).offsetMax = Vector2.zero;(obj.transform as RectTransform).offsetMin = Vector2.zero;//得到预设体身上的面板脚本T panel = obj.GetComponent<T>();// 处理面板创建完成后的逻辑if (callBack != null)callBack(panel);panel.ShowMe();//把面板存起来panelDic.Add(panelName, panel);});}/// <summary>/// 隐藏面板/// </summary>/// <param name="panelName"></param>public void HidePanel(string panelName){if (panelDic.ContainsKey(panelName)){panelDic[panelName].HideMe();GameObject.Destroy(panelDic[panelName].gameObject);panelDic.Remove(panelName);}}/// <summary>/// 得到某一个已经显示的面板 方便外部使用/// </summary>public T GetPanel<T>(string name) where T : BasePanel{if (panelDic.ContainsKey(name))return panelDic[name] as T;return null;}/// <summary>/// 给控件添加自定义事件监听/// </summary>/// <param name="control">控件对象</param>/// <param name="type">事件类型</param>/// <param name="callBack">事件的响应函数</param>public static void AddCustomEventListener(UIBehaviour control, EventTriggerType type, UnityAction<BaseEventData> callBack){EventTrigger trigger = control.GetComponent<EventTrigger>();if (trigger == null)trigger = control.gameObject.AddComponent<EventTrigger>();EventTrigger.Entry entry = new EventTrigger.Entry();entry.eventID = type;entry.callback.AddListener(callBack);trigger.triggers.Add(entry);}}
