目录
前言
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;//加载根节点的Prefab
Canvas_Main = UI.Find("Canvas_Main");//找到三个主要节点,以备之后放入相应的Prefab
Canvas_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.position
rectTransform.localScale = Vector3.one; //对应节点的Scale
rectTransform.offsetMax = Vector2.zero; //对应Right和Bottom
rectTransform.offsetMin = Vector2.zero; //对应Left和Top
panel = 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]; //那就先取得这个panel
panel.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()
{
//使用字典迭代器遍历所有面板,也可以用foreach
Dictionary<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节点下的),加载后的名字按照上面初始化工具中设置的名字:
效果就是本文一开始的效果。