在 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
    }
}

发布了71 篇原创文章 · 获赞 160 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/wangjiangrong/article/details/103995168
今日推荐