1.引入
前面我们用一个UI基类来对一个Panel下的所有组件进行管理,现在我们要对一个Canvas下的所有Panel进行统一管理,即显示和隐藏Panel
一般有两种办法进行显示和隐藏Panel:
1.设置Panel的Active(SetActive)为true或者false,即显示或隐藏Panel
2.将Panel做成预设体,进行实例化和销毁Panel
前者如果面板过多,会占用过多的内存,所以我们选择后者
2.思路
写一个UIManager
为了统一管理(有时需要显示的Panel不止一个),我们用一个字典来存放显示的Panel,即是:
Dictionary<string, PanelBase> dic = new Dictionary<string, PanelBase>();
注:PanelBase为前面的UI基类,即所有Panel脚本的父类
2.1显示面板的实现:
2.1.1那么我们在实例化Panel时候也需要考虑层级问题,为此,我们将Canvas进行如下操作:
此处的Bottom、Medium、Top,System分别对应显示的不同层级。在实例化时只要放在需要显示的对应层级下(作为对应层的子物体)
注:在hierarchy面板中的UI层越靠前越先渲染,即越底层,可能被遮挡。
为了方便,我们将Canvas和EventSystem也做成预设体,在UIManager的构造函数中实例化,因为是单例,所以只会被实例化一次,即Cavas和EventSystem也只会被实例化一次。
2.1.2 实例化面板后,我们通常要对面板的一些信息进行更新,所以函数的参数还可以设置一个委托在实例化后调用(因为此处是异步加载资源,所以在外部不知道什么时候加载完毕,需要专门设置一个参数调用实例化后的函数)
2.1.3 面板显示函数:
/// <summary>
/// 显示面板
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <param name="layout"></param>
/// <param name="action"></param>
public void ShowPanel<T>(string name,UI_Layout layout= UI_Layout.SYSTEM, UnityAction<T> action=null) where T: PanelBase
{
//如果字典中存在该面板,即已经在显示该面板
if(dic!=null&&dic.ContainsKey(name))
{
T t = dic[name].GetComponent<T>();
if(action!=null)
action(t);
return;
}
//确定显示的层级
Transform father= canvas.Find("System");
ResourcesManager.GetInstance().LoadResourceAsync<GameObject>("UI/" + name, (o) =>
{
switch(layout)
{
case UI_Layout.BOTTOM: father = canvas.Find("Bottom");break;
case UI_Layout.MEDIUM: father = canvas.Find("Medium");break;
case UI_Layout.TOP: father = canvas.Find("Top");break;
}
//设置显示的参数
o.name = name;
o.transform.SetParent(father);
o.transform.localPosition = Vector3.zero;
o.transform.localScale = Vector3.one;
(o.transform as RectTransform).offsetMax = Vector2.zero;
(o.transform as RectTransform).offsetMin = Vector2.zero;
//执行显示后的操作
T t = o.GetComponent<T>();
if(action!=null)
action(t);
//存储到字典中[注意此处只存脚本是因为我们对panel的操作一般体现在调用panel的方法]
dic.Add(name, t);
});
}
2.2隐藏面板
只需进行销毁和从字典中移除的操作即可。
3.所有代码
public class UIManager : SingeCaseBase<UIManager>
{
//面板层级
public enum UI_Layout {
TOP,
BOTTOM,
MEDIUM,
SYSTEM,
};
Transform canvas;
/// <summary>
/// 创建Canvas和EventSystem
/// </summary>
public UIManager()
{
canvas = ResourcesManager.GetInstance().LoadResource<GameObject>("UI/Canvas").transform;
GameObject.DontDestroyOnLoad(canvas);
GameObject eventSystem = ResourcesManager.GetInstance().LoadResource<GameObject>("UI/EventSystem");
GameObject.DontDestroyOnLoad(eventSystem);
}
Dictionary<string, PanelBase> dic = new Dictionary<string, PanelBase>();
/// <summary>
/// 显示面板
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <param name="layout"></param>
/// <param name="action"></param>
public void ShowPanel<T>(string name,UI_Layout layout= UI_Layout.SYSTEM, UnityAction<T> action=null) where T: PanelBase
{
//如果字典中存在该面板,即已经在显示该面板
if(dic!=null&&dic.ContainsKey(name))
{
T t = dic[name].GetComponent<T>();
if(action!=null)
action(t);
return;
}
//确定显示的层级
Transform father= canvas.Find("System");
ResourcesManager.GetInstance().LoadResourceAsync<GameObject>("UI/" + name, (o) =>
{
switch(layout)
{
case UI_Layout.BOTTOM: father = canvas.Find("Bottom");break;
case UI_Layout.MEDIUM: father = canvas.Find("Medium");break;
case UI_Layout.TOP: father = canvas.Find("Top");break;
}
//设置显示的参数
o.name = name;
o.transform.SetParent(father);
o.transform.localPosition = Vector3.zero;
o.transform.localScale = Vector3.one;
(o.transform as RectTransform).offsetMax = Vector2.zero;
(o.transform as RectTransform).offsetMin = Vector2.zero;
//执行显示后的操作
T t = o.GetComponent<T>();
if(action!=null)
action(t);
//存储到字典中[注意此处只存脚本是因为我们对panel的操作一般体现在调用panel的方法]
dic.Add(name, t);
});
}
/// <summary>
/// 隐藏面板
/// </summary>
/// <param name="name"></param>
public void HidePanel(string name)
{
if(dic.ContainsKey(name))
{
//销毁并移除
GameObject.Destroy(dic[name].gameObject);
dic.Remove(name);
}
}
}