在 ILRuntime 的基礎上,搭建一個簡單的UI系統(三) 層級關係

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

 

發佈了72 篇原創文章 · 獲贊 166 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章