框架参考:https://blog.csdn.net/leonardo_Davinci/article/details/78401907
UIManager - UIPanel(面板层级)
自定义Panel类(继承UIPanel) - UIPanel - OnTriggerEvent(按控件钮)
UIManager 获取/管理所有的UIPanel(GameObject.FindObjectsOfType),提供面板初始化、面板显隐、面板隐藏、按名字获取面板等的全局方法,该类为单例类,拖入场景任意位置仅需一个
UIPanel:不需要添加至场景,用做各自面板的基类便于UIManger进行索引,管理该面板下的按钮等UI控件,提供按名字获取子控件的方法
OnTriggerEvent:添加至所有按钮控件上
FilePanel、LivePanel、SettingPanel等:添加在各自的面板物体下,继承UIPanel,初始化UIPanel的按钮字典后为该面板下的按钮添加触发事件
1.单例基类
public class Singleton<T> : MonoBehaviour where T : Component{private static T target;public static T Intance{get{target = GameObject.FindObjectOfType(typeof(T)) as T;if (target == null){GameObject go = new GameObject();target = go.AddComponent<T>();}return target;}}}
2.面板管理器
using UnityEngine.EventSystems;public class UIManager : Singleton<UIManager>{//创建一个字典来保存所有 PanelDictionary<string, UIPanel> panels = new Dictionary<string, UIPanel>();public void Init(){UIPanel[] items = GameObject.FindObjectsOfType<UIPanel>();for (int i = 0; i < items.Length; i++){UIPanel go = items[i];if (!panels.ContainsKey(go.name)){panels.Add(go.name, go);go.gameObject.SetActive(false);}}}//获取UIPanelpublic UIPanel GetUIPanel(string name){if (panels.ContainsKey(name)){return panels[name];}return null;}//UIPanel组件是否激活public void IsActive(string name, bool isActive){GameObject go = panels[name].gameObject;if (go == null){Debug.Log("你要查找的物体丢");return;}go.gameObject.SetActive(isActive);}// 面板开关切换public void ChangePanel(string name){GameObject go = panels[name].gameObject;if (go == null){Debug.Log("你要查找的物体丢");return;}//第一次点击按钮的执行if (go.gameObject.activeInHierarchy == false){hideAllMenuBarPanels();go.gameObject.SetActive(true);}else {//两次点击同一按钮的执行EventSystem.current.SetSelectedGameObject(null);hideAllMenuBarPanels();}}public void ShowMenuBar(){IsActive("菜单面板", true);}public void hideAllMenuBarPanels(){UIPanel[] items = GameObject.FindObjectsOfType<UIPanel>();for (int i = 0; i < items.Length; i++){if (items[i].name != "菜单面板"){items[i].gameObject.SetActive(false);}}}}
3.面板基类
public class UIPanel : MonoBehaviour{/// <summary>/// 管理所有需要监听的子物体/// </summary>Dictionary<string, OnTriggerEvent> items = new Dictionary<string, OnTriggerEvent>();public void Start(){}/// <summary>/// 根据名字在字典当中获取子物体/// </summary>public OnTriggerEvent GetTrigger(string name){if (items.ContainsKey(name))return items[name];return null;}public void FindAllButtonInit(Transform transform){//调用Find方法找到这个Panel下面带有OnTriggerEvent组件的所有子物体FindAll(transform);}public void FindInit(){Find(transform);}//查找子物体带OnTriggerEvent组件的物体 记录名字private void Find(Transform t){OnTriggerEvent item = t.GetComponent<OnTriggerEvent>();if (item != null){string name = item.gameObject.name;if (!items.ContainsKey(name)){items.Add(name, item);}}for (int i = 0; i < t.childCount; i++){Find(t.GetChild(i));}}private void FindAll(Transform t){OnTriggerEvent[] items = t.GetComponentsInChildren<OnTriggerEvent>();if (items != null){foreach (var child in items){string name = child.gameObject.name;if (!this.items.ContainsKey(name)){this.items.Add(name, child);}}}}}
4.按钮触发监听
using UnityEngine.Events;using UnityEngine.EventSystems;public class OnTriggerEvent : MonoBehaviour,IPointerClickHandler, IPointerUpHandler, IPointerEnterHandler,IPointerExitHandler{//通过委托事件让UIPanel来分配事件[SerializeField] private UnityEvent onClick=null;public delegate void ClickListener();public event ClickListener onPointerClick;public event ClickListener onPointerUp;public event ClickListener onPointerEnter;public event ClickListener onPointerExit;public void OnPointerClick(PointerEventData eventdata){if (onPointerClick != null)onPointerClick();onClick.Invoke();}public void OnPointerUp(PointerEventData eventdata){if (onPointerUp != null)onPointerUp();}public void OnPointerEnter(PointerEventData eventData){if (onPointerEnter != null)onPointerEnter();}public void OnPointerExit(PointerEventData eventData){if (onPointerExit != null)onPointerExit();}}
5.具体面板 菜单面板
该面板较为特殊,初始化后菜单栏需单独显示:UIManager.Intance.ShowMenuBar();
身为所有物体的父层级findAll方法找到所有按钮:FindAllButtonInit(transform); 这样在执行字典初始化方法后其对应的UIPanel的字典内存放该菜单栏内所有的按钮,用于监听鼠标在菜单栏以及下拉栏的按钮外部点击事件后隐藏所有面板
using UnityEngine.EventSystems;using UnityEngine.UI;public class MenuPanel : UIPanel{private OnTriggerEvent filePanel;private OnTriggerEvent toolsPanel;private OnTriggerEvent setttingPanel;private OnTriggerEvent livePanel;new void Start(){FindAllButtonInit(transform);UIManager.Intance.Init();//找到所有面板UIManager.Intance.ShowMenuBar();//默认显示菜单栏filePanel = GetTrigger("文件(按钮)");toolsPanel = GetTrigger("工具(按钮)");setttingPanel = GetTrigger("首选项(按钮)");livePanel = GetTrigger("直播助手(按钮)");filePanel.onPointerClick += FilePanel;toolsPanel.onPointerClick += ToolsPanel;setttingPanel.onPointerClick += SettingPanel;livePanel.onPointerClick += LivePanel;}private void FilePanel(){UIManager.Intance.ChangePanel("文件面板");}private void ToolsPanel(){UIManager.Intance.ChangePanel("工具面板");}private void SettingPanel(){UIManager.Intance.ChangePanel("首选项面板");}private void LivePanel(){UIManager.Intance.ChangePanel("助手面板");}private void Update(){//点击菜单栏以外区域的执行if (Input.GetMouseButtonDown(0)){if (EventSystem.current.currentSelectedGameObject ==null) { UIManager.Intance.hideAllMenuBarPanels(); }else if (GetTrigger(EventSystem.current.currentSelectedGameObject.name) == null){UIManager.Intance.hideAllMenuBarPanels();}}}}
