Unity游戏UI框架(四):模态窗体管理

来源:互联网 发布:淘宝联盟佣金 编辑:程序博客网 时间:2024/06/05 06:58

我们在开发UI窗体时,对于“弹出窗体”往往因为需要玩家优先处理弹出小窗体,则要求玩家不能(无法)点击“父窗体”,这种窗体就是典型的“模态窗体”。在此设计了四种模式类型:完全透明、半透明、低透明度、透明且可以穿透。

  • 完全透明不能穿透
    这里写图片描述

  • 半透明不能穿透
    这里写图片描述

  • 低透明度,不能穿透
    这里写图片描述

模态窗体实现原理

在弹出窗体的后面增加一层“UI遮罩窗体”,当需要弹出特定模态窗体时,脚本自动控制“UI遮罩窗体”的“层级”,把弹出模特窗体与普通窗体之间进行隔离,起到突出显示与遮挡用户点击其他窗体的作用。原理如下图所示:
这里写图片描述

在上图左边的层级视图中,有一个“_UIMaskPanel”的特殊窗体,这就是“UI遮罩窗体”,在不需要弹出显示的时候,这个窗体是“禁用”状态。 为了更好适用不同开发需求,对于弹出窗体,我们上面定义了关于弹出窗体的不同性质: 完全透明、半透明、低透明度、透明且可以穿透。 这四种类型功能的实现原理是控制“_UIMaskPanel”的颜色数值以及透明度实现的,见下图所示:
这里写图片描述

说明: 上图右边属性就是“UI遮罩窗体”的属性栏,笔者通过脚本控制Image组件的Color 组件,来实现”模态窗体”的不同显示性质。

原理讲完,贴出控制代码如下:

/// <summary>/// UI遮罩层管理器/// </summary>public class UIMaskMgr : MonoBehaviour{    /// <summary>    /// 单例    /// </summary>    private static UIMaskMgr _instance = null;    /// <summary>    /// UI根节点对象    /// </summary>    private GameObject _GoCanvasRoot = null;    /// <summary>    /// UI脚本节点对象    /// </summary>    private Transform _TraUiScripts = null;    /// <summary>    /// 顶层面板:UI根节点对象    /// </summary>    private GameObject _GoTopPanel = null;    /// <summary>    /// 遮罩面板    /// </summary>    private GameObject _GoMaskPanel = null;    /// <summary>    /// UI摄像机    /// </summary>    private Camera _UICamera;    /// <summary>    /// UI摄像机原始的“层深”    /// </summary>    private float _OriginalUICameralDepth;    public static UIMaskMgr GetInstance()    {        if (!_instance)        {            _instance = new GameObject("_UIMaskMgr").AddComponent<UIMaskMgr>();        }        return _instance;    }    void Awake()    {        _GoCanvasRoot = GameObject.FindGameObjectWithTag(SysDefine.SYS_TAG_CANVAS);        _TraUiScripts = GameTools.FindTheChildNode(_GoCanvasRoot, SysDefine.SYS_SCRIPTMANAGER_NODE);        //把本脚本实例,作为“脚本节点对象”的子节点。        GameTools.AddChildNodeToParentNode(_TraUiScripts, transform);        //得到“顶层面板”、“遮罩面板”        _GoTopPanel = _GoCanvasRoot;        _GoMaskPanel = GameTools.FindTheChildNode(_GoCanvasRoot, SysDefine.SYS_MASKPANEL_NODE).gameObject;        //得到UI摄像机原始的“层深”        _UICamera = GameTools.FindTheChildNode(_GoCanvasRoot, SysDefine.SYS_UICAMERA_NODE).gameObject.GetComponent<Camera>();        if (_UICamera)        {            //得到UI摄像机原始“层深”            _OriginalUICameralDepth = _UICamera.depth;        }        else        {            Debug.Log(GetType() + "/Start()/UI_Camera is Null!,Please Check! ");        }    }    /// <summary>    /// 设置遮罩状态    /// </summary>    /// <param name="goDisplayUIForms">需要显示的UI窗体</param>    /// <param name="lucenyType">显示透明度属性</param>    public void SetMaskWindow(GameObject goDisplayUIForms, UIFormLucenyType type = UIFormLucenyType.Lucency)    {        //顶层窗体下移:SetAsLastSibling:设置为同级最后        _GoTopPanel.transform.SetAsLastSibling();        //启用遮罩窗体以及设置透明度        switch (type)        {            //完全透明,不能穿透            case UIFormLucenyType.Lucency:                _GoMaskPanel.SetActive(true);                Color newColor = new Color(1.0f, 1.0f, 1.0f, 0.0f);                _GoMaskPanel.GetComponent<Image>().color = newColor;                break;            //半透明,不能穿透            case UIFormLucenyType.Translucence:                _GoMaskPanel.SetActive(true);                Color newColor2 = new Color(220 / 255F, 220 / 255F, 220 / 255F, 50 / 255F);                _GoMaskPanel.GetComponent<Image>().color = newColor2;                break;            //低透明,不能穿透            case UIFormLucenyType.ImPenetrable:                _GoMaskPanel.SetActive(true);                Color newColor3 = new Color(50 / 255F, 50 / 255F, 50 / 255F, 200F / 255F);                _GoMaskPanel.GetComponent<Image>().color = newColor3;                break;            //可以穿透            case UIFormLucenyType.Pentrate:                if (_GoMaskPanel.activeInHierarchy)                {                    _GoMaskPanel.SetActive(false);                }                break;            default:                break;        }        //遮罩窗体下移        _GoMaskPanel.transform.SetAsLastSibling();        //显示窗体的下移        goDisplayUIForms.transform.SetAsLastSibling();        //增加当前UI摄像机的层深(保证当前摄像机为最前显示)        if (_UICamera)        {            _UICamera.depth = _UICamera.depth + 100;        }    }    /// <summary>    /// 取消遮罩状态    /// </summary>    public void CancelMaskWindow()    {        //顶层窗体上移        _GoTopPanel.transform.SetAsFirstSibling();        //禁用遮罩窗体        if (_GoMaskPanel.activeInHierarchy)        {            //隐藏            _GoMaskPanel.SetActive(false);        }        //恢复当前UI摄像机的层深         if (_UICamera != null)        {            _UICamera.depth = _OriginalUICameralDepth;  //恢复层深        }    }}



关于上述定义的UIMaskMgr.cs 脚本代码 ,在“BaseUIForm.cs” 中做了封装,使其可以在框架中自动管理,无需框架外客户程序的处理。BaseUIForm.cs 代码如下:

/// <summary>/// UI窗体基类/// </summary>public class BaseUIForm : MonoBehaviour {    /// <summary>    /// 当前(基类)窗体类型    /// </summary>    private UIType _CurrentUIType = new UIType();    /// <summary>    /// 属性_当前UI窗体类型    /// </summary>    internal UIType CurrentUIType    {        get { return _CurrentUIType;  }        set { _CurrentUIType = value; }    }    /// <summary>    /// UI界面显示    /// </summary>    public virtual void Display()    {        this.gameObject.SetActive(true);        //设置模态窗体调用(必须是弹出窗体)        if (_CurrentUIType.UIForm_Type == UIFormType.PopUp)        {            UIMaskMgr.GetInstance().SetMaskWindow(this.gameObject, _CurrentUIType.UIForm_LucencyType);        }    }    /// <summary>    /// UI界面隐藏(不在“栈”集合中)    /// </summary>    public virtual void Hiding()    {        this.gameObject.SetActive(false);        //取消模态窗体调用        if (_CurrentUIType.UIForm_Type == UIFormType.PopUp)        {            UIMaskMgr.GetInstance().CancelMaskWindow();        }    }    /// <summary>    /// UI界面重新显示    /// </summary>    public virtual void Redisplay()    {        this.gameObject.SetActive(true);        //设置模态窗体调用(必须是弹出窗体)        if (_CurrentUIType.UIForm_Type == UIFormType.PopUp)        {            UIMaskMgr.GetInstance().SetMaskWindow(this.gameObject, _CurrentUIType.UIForm_LucencyType);        }    }    /// <summary>    /// //页面冻结(还在“栈”集合中),窗体显示在其他窗体下面    /// </summary>    public virtual void Freeze()    {        this.gameObject.SetActive(true);    }}

以上所讲解的是大体实现思路,还有很多的小细节由于时间关系没有披露,具体的项目后面章节会提供下载

转载地址:刘老师讲Unity

原创粉丝点击