目录
前言
UIManger的实现
1. 需要用到的变量和数据
2. 在构造中的工作
3. 初始化面板
4. 显示面板
5. 隐藏面板和隐藏所有面板
6. 其他小工具
在场景中实现
1. 不同面板的类型设置
2. 场景中的设置
前言
接前篇,上一篇已经有了UITools.cs其中定义了UI面板需要使用的基本工具,如:初始化UI节点、遍历所有节点、在按键上添加EventTrigger等,以及各种类型UI面板继承UITools的个性化工具,比如MainUI.cs。本篇要实现一个简单的管理工具UIManager,并使用它的工具实现面板的初始化、显示、隐藏等。功能比较简单,最终效果如下(这里的动画效果是原文件中的动画):
UIManger的实现
作为一个管理器类,UIManager也需要继承单例,关于单例的内容详见():
public class UIManager : Single<UIManager>
{}
在UIManager中要实现的功能有:1. 初始化时在场景中载入UI预制体;2. 获取UI节点上的重要组件(如Canvas),以备后用;3. 初始化面板,加载UI预制体到相应节点下,并放置到合理的屏幕位置;4. 显示/隐藏/消除面板等工具;5. 根据项目设置其他实用工具。以下为具体代码:
1. 需要用到的变量和数据
public enum PanelType //面板的类型:主面板、副面板、弹窗{Main,Extra,UP}private string uiPath = "UI/"; //加载UI预制体的路径,“Resource/UI”private Transform UI; //获取场景中的UI根节点private Transform Canvas_Main; //获取UI的各个节点,以便于控制位置等private Transform Canvas_Extra;private Transform Canvas_UP;private Camera uiCamera; //获取UI相机private Canvas Cvs_Main; //获取主面板上的Canvas组件(其他面板本例中暂不需要)private RectTransform rectTransform_Main; //获取主面板RectTransform组件,为了安排位置Dictionary<string, UITools> UIList; //管理所有的面板的字典
以上的变量均可以封装使用,且将改为只读属性。
2. 在构造中的工作
其中的UI、Canvas_Main等节点设置见上一篇(UI管理1):
public UIManager(){UIList= new Dictionary<string, UITools>(); //实例化字典UI = Resload.Instance.LoadPrefab(uiPath + "UI").transform;//加载根节点的PrefabCanvas_Main = UI.Find("Canvas_Main");//找到三个主要节点,以备之后放入相应的PrefabCanvas_Extra = UI.Find("Canvas_Extra");Canvas_UP = UI.Find("Canvas_UP");Cvs_Main = Canvas_Main.GetComponent<Canvas>();//载入主节点上的几个重要组件rectTransform_Main = Canvas_Main.GetComponent<RectTransform>();uiCamera= UI.Find("UICamera").GetComponent<Camera>();Object.DontDestroyOnLoad(UI.gameObject); //设置在场景切换时,UI节点不消除}
3. 初始化面板
——将面板的预制体载入UI的相应节点中,并设置位置
//初始化面板public T InitPanel<T>(string panelName,string prefabName,UnityAction action=null,PanelType type=PanelType.Extra) where T : UITools{UITools panel; if (!IsHavePanel(panelName)) //使用小工具判断字典中是否有该面板{//没有该面板,那么再加载预制体GameObject GO = Resload.Instance.LoadPrefab(uiPath + prefabName);GO.name = panelName; //让场内的节点取名为自定义的名字RectTransform rectTransform =GO.GetComponent<RectTransform>();//获取面板上的RectTransform,以便于安排位置//设置不同的类型的面板对应地显示在哪个节点下面:switch (type){case PanelType.Main: rectTransform.SetParent(Canvas_Main); break; case PanelType.Extra: rectTransform.SetParent(Canvas_Extra); break;case PanelType.UP: rectTransform.SetParent(Canvas_UP); break;}//设置面板位置,可以根据不同情况调整rectTransform.localPosition = Vector3.zero; //对应节点的Transform.positionrectTransform.localScale = Vector3.one; //对应节点的ScalerectTransform.offsetMax = Vector2.zero; //对应Right和BottomrectTransform.offsetMin = Vector2.zero; //对应Left和Toppanel = GO.GetComponent<T>() ?? GO.AddComponent<T>();//检测本脚本挂载的GameObject上是否有挂载相应的工具类,//比如MainUI就要挂载MainUi.cs,没有就加载一个//赋值完成后,将这个Panel加到字典中UIList.Add(panelName, panel); //panelName:名字;panel:比如MainUI类panel.Init(action); //初始化,这个Init是在UITools中定义的Init}else //如果字典里已有{panel = UIList[panelName]; //那就先取得这个panelpanel.transform.SetAsLastSibling(); //然后加载到UI节点的最后面(显示在最前面)}return panel as T; }
其中,判断面板是否存在于字典的小工具:
bool IsHavePanel(string panelName){return UIList.ContainsKey(panelName);}
4. 显示面板
public T ShowPanel<T>(string panelName, string prefabName, UnityAction action = null,PanelType type = PanelType.Extra) where T : UITools{UITools panel; if(!IsHavePanel(panelName)){//先判断字典里是否有这个面板,没有的话先初始化panel = InitPanel<T>(panelName, prefabName, action, type);}else{//如果字典里已经有该面板了,就从字典中查找panel = UIList[panelName];if(panel!=null){//找到了,就将它显示在最前面panel.transform.SetAsLastSibling();}else{foreach(var panelTemp in UIList) //panel已经在场景中显示,但字典中没有获取到{Debug.Log(panelTemp.Key+"不存在字典中");Debug.Log(panelTemp.Value + "不存在字典中");}}}panel.Show(action);return panel as T;}
5. 隐藏面板和隐藏所有面板
public void HidePanel(string panelName){if(IsHavePanel(panelName)){UIList[panelName].Hide();}}public void HideAllPanel(){//使用字典迭代器遍历所有面板,也可以用foreachDictionary<string,UITools>.Enumerator enumerator= UIList.GetEnumerator();while(enumerator.MoveNext()){UIList[enumerator.Current.Key].Hide();}}
6. 其他小工具
——比如获取组件,这个组件是挂载在每个面板上的继承UITools的类型,比如MainUi.cs;比如加载UI预制体工具:
public T GetPanel<T>(string panelName) where T: UITools{//获取面板的类型(继承UITools)if (IsHavePanel(panelName))return UIList[panelName] as T;return null;}public GameObject LoadUIPrefab(string prefabName,Transform parent, string name=null){//从预制体文件夹中加载UI预制体GameObject gameObject = Resload.Instance.LoadPrefab(uiPath + prefabName);gameObject.name=name!=string.Empty?name:prefabName; //传入的名字是否为空,空就用prefabName//之后就如初始化时一样,调整位置、缩放等RectTransform rectTransform=gameObject.transform as RectTransform;rectTransform.SetParent(parent); //将rectTransform.localPosition = Vector3.zero;rectTransform.localScale = Vector3.one;rectTransform.offsetMax = Vector3.zero;rectTransform.offsetMin = Vector3.zero;return gameObject;}
以上是本次UI管理中需要用到的对面板操作的工具,当然这次使用的面板都比较简单,在复杂项目中需要用到的管理方法更多。
在场景中实现
1. 不同面板的类型设置
场景中需要加载3个面板:MAIN、EXTRAS、EXIT,每一个面板都有各自的管理类,继承UITools,主面板MAIN的管理器上一篇中已经定义,并且将它挂载在MAIN面板上,另外需要控制EXTRAS和EXIT的,实现的功能少,因此都挺简单:
(1)ExtraUi.cs挂载在EXTRAS面板上:
public class ExtraUi :UITools
{public override void Init(UnityAction action = null){//初始化EXTRA面板base.Init(action);TMP_Text text = GetComponent<TMP_Text>("TextTooltip");text.text = "Extra面板初始化成功";//给每一个图片按钮加上事件,用于打开链接AddEventTrigger("Btn_CCP", EventTriggerType.PointerClick, CCP);AddEventTrigger("Btn_Clean1", EventTriggerType.PointerClick, Clean1);AddEventTrigger("Btn_Essence", EventTriggerType.PointerClick, Essence);AddEventTrigger("Btn_SciFi", EventTriggerType.PointerClick, SciFi);}private void CCP(BaseEventData data){Application.OpenURL("http://u3d.as/1JZG");}private void SciFi(BaseEventData data){Application.OpenURL("http://u3d.as/1AaR");}private void Clean1(BaseEventData data){Application.OpenURL("http://u3d.as/1hTi");}private void Essence(BaseEventData data){Application.OpenURL("http://u3d.as/1t11");}}
(2)ExitUi.cs挂载在EXIT预设体面板上
public class ExitUi :UITools
{public override void Init(UnityAction action = null){base.Init(action);AddEventTrigger("Btn_No", EventTriggerType.PointerClick, OnEventBack);AddEventTrigger("Btn_Yes", EventTriggerType.PointerClick, OnEventBye);}private void OnEventBack(BaseEventData data){//如果选择NO按钮,隐藏Exit面板UIManager.Instance.HidePanel("ExitPanel");}private void OnEventBye(BaseEventData data){//如果选择Yes按钮,把所有面板都关了UIManager.Instance.DestroyAllPanel();}
}
(3)建立一个Test.cs作为控制文件,随意挂在场景内的节点。作用是在场景初始化时调用UIManager并使用ShowPanel工具加载一个预制体MAIN,在场景中命名为MainPanel,由于这个面板的类型是Main,所以将它加载到Canvas_Main节点下:
public class Test : MonoBehaviour
{void Start(){UIManager.Instance.ShowPanel<MainUi>("MainPanel", "MAIN",null, UIManager.PanelType.Main); }
2. 场景中的设置
(1) 预制体文件夹和每个预制体的节点结构,上一篇中已经介绍过了。
(2)场景中只要有一个Test.cs,另外还需要一个Resload工具,加载时需要使用(详见ResourceManager)
(3)场景运行时,所有节点自动加载到相应的节点下(如果没有明确设置,默认是在Canvas_Extra节点下的),加载后的名字按照上面初始化工具中设置的名字:
效果就是本文一开始的效果。