前面大致講解了下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
}
}