前面大致讲解了下UIPanel和UIView的创建和使用,这篇我们主要来讲解下UIPanel之间的层级关系。
基本上我们一个完整的界面是一个UIPanel对象,正常来说,显示一个新的UIPanel都会覆盖在前一个之上。但是有些特殊的UI我们需要特殊的处理,例如几乎每个界面都会有的货币栏UI,你可以在每个UIPanel都添加,也可以单独做成一个UIPanel,但是要始终保持在别的UIPanel之上。再比如提示框或者其他弹出框类型的UI,他们又会在普通UI和货币栏UI之上。甚至有的可能会有一些系统公告的走马灯显示在所有UI的上层。
在Demo中,我们就简单的将其分为三个层次:
Default:存放普通的UIPanel,显示最新加载的UIPanel
Banner:存放UI顶部的货币栏个人信息等,始终显示在Default之上
Popup:存放一些弹窗UI,例如对话框,菊花框等等
搞清楚要实现什么后,接下来我们来看看如何实现我们想要的效果。首先UGUI的Canvas上有一个Order in Layer属性,可以用来控制每个Canvas的渲染顺序,值越大的渲染的越晚,也就是显示在越前面。
正好我们可以利用这个特性,来处理我们上面的三个层次,每个层次一个Canvas,分别为DefaultCanvas = 0,BannerCanvas = 1,PopupCanvas = 2。(注,除了Order in Layer属性外,三个Canvas的其他属性要相同)
然后在每个Canvas中,我们如果来保证新显示的UI显示在最上方呢,我们都知道UGUI的显示顺序是Hierarchy面板中的排列顺序,排在后面的显示在排在前面的之上。在我们之前的UIPanel设计中,由于关闭的页面不销毁只是隐藏,再次显示的时候只是SetActive(true)因此就会有一个问题。加入我们先显示MallPanel,然后关闭之后去显示MessagePanel,此时的排序MessagePanel在MallPanel下面。若我们有个需求是MessagePanel上加个按钮跳转到MallPanel,那么按照之前的逻辑,仅仅将MallPanel.SetActive(true),不去改变前后顺序,我们依旧无法看见它。因此我们需要加最新Show的UIPanel,放到Canvas中的最下面。RectTransform.SetAsLastSibling();可以很好的帮我们实现这个功能,我们在Show的时候调用下即可。
public class UIPanel : UIView
{
......
public override void Show()
{
base.Show();
rectTransform.SetAsLastSibling();
}
......
}
大致效果如下
添加一个枚举用于表示层级
public enum EUIPanelDepth
{
Default,
Banner,
Popup,
}
然后在之前的ShowPanel方法中添加该枚举参数,根据值判断该UIPanel的父节点为哪个Canvas
public void ShowPanel<T>(EUIPanelDepth depth, Action<T> callback, object data) where T : UIPanel
public void LoadPanel(EUIPanelDepth depth, string url, object data, Action callback)
{
......
panel.Load(() =>
{
if (panel.isLoaded)
{
if(depth == EUIPanelDepth.Banner)
panel.rectTransform.SetParentAndResetTrans(m_bannerCanvas);
else
panel.rectTransform.SetParentAndResetTrans(m_defaultCanvas);
callback?.Invoke();
}
......
});
}
BannerPanel逻辑和之前的UIPanel一样,只是放在的Canvas不同而已,没啥多说的。但是Dialog方面有些东西需要特殊处理。
由于一般Dialog在同一时间可能存在多个,而我们之前UIPanel的设计是在场景中只会存在一个,因此我们可以用UIView来处理。同时不显示的时候直接销毁该GameObject
namespace Hotfix.UI
{
public class DialogView : UIView
{
Text m_titleText;
Text m_contentText;
GameObject m_buttonGroupOne;
GameObject m_buttonGroupTwo;
Button m_groupOneConfirmButton;
Button m_groupTwoConfirmButton;
Button m_groupTwoCancelButton;
Action m_confirmCallback;
DialogType m_type;
public DialogView(GameObject go) : base(go)
{
parent = UIPanelManager.Instance.popupCanvas;
rectTransform.ResetTrans();
}
public override void Init()
{
base.Init();
m_groupOneConfirmButton.onClick.AddListener(OnCancelButtonClick);
m_groupTwoConfirmButton.onClick.AddListener(OnConfirmButtonClick);
m_groupTwoCancelButton.onClick.AddListener(OnCancelButtonClick);
}
public void Setting(DialogType type, string title, string content, Action confirmCallback)
{
if(type == DialogType.OnlyConfirm)
{
m_buttonGroupOne.SetActive(true);
m_buttonGroupTwo.SetActive(false);
}
else
{
m_buttonGroupOne.SetActive(false);
m_buttonGroupTwo.SetActive(true);
}
m_titleText.text = title;
m_contentText.text = content;
m_confirmCallback = confirmCallback;
}
public override void GetChild()
{
base.GetChild();
m_titleText = transform.Find("BGImage/TitleText").GetComponent<Text>();
m_contentText = transform.Find("BGImage/ContentText").GetComponent<Text>();
m_buttonGroupOne = transform.Find("BGImage/ButtonGroupOne").gameObject;
m_buttonGroupTwo = transform.Find("BGImage/ButtonGroupTwo").gameObject;
m_groupOneConfirmButton = transform.Find("BGImage/ButtonGroupOne/ConfirmButton").GetComponent<Button>();
m_groupTwoConfirmButton = transform.Find("BGImage/ButtonGroupTwo/ConfirmButton").GetComponent<Button>();
m_groupTwoCancelButton = transform.Find("BGImage/ButtonGroupTwo/CancelButton").GetComponent<Button>();
}
void OnCancelButtonClick()
{
Destroy();
}
void OnConfirmButtonClick()
{
Destroy();
m_confirmCallback?.Invoke();
}
}
}
调用的方法为
namespace Hotfix.UI
{
public enum DialogType
{
OnlyConfirm,
ConfirmAndCancel
}
public static class UIHelper
{
static GameObject m_dialogViewPrefab;
#region Dialog
public static void ShowDialogConfirmAndCancel(string title, string content, Action confirmCallback = null)
{
ShowDialog(DialogType.ConfirmAndCancel, title, content, confirmCallback);
}
public static void ShowDialogOnlyConfirm(string title, string content, Action confirmCallback = null)
{
ShowDialog(DialogType.OnlyConfirm, title, content, confirmCallback);
}
public static void ShowDialog(DialogType type, string title, string content, Action confirmCallback = null)
{
if(m_dialogViewPrefab == null)
m_dialogViewPrefab = Resources.Load("DialogView") as GameObject;
GameObject go = GameObject.Instantiate(m_dialogViewPrefab) as GameObject;
DialogView view = UIViewManager.Instance.CreateView<DialogView>(go);
view.Setting(type, title, content, confirmCallback);
view.Show();
}
#endregion
}
}