UI框架-UIManager

作者: 一云小窝 | 来源:发表于2018-07-10 23:34 被阅读40次

    目录

    1. UI框架介绍
    2. 保存面板信息
    3. 解析面板信息,开发配套数据模型
    4. 开发公共面板类BasePanel
    5. 开发UIManager核心管理类
    6. 开发菜单面板类和背包类使用UIManager
    7. 结束

    一,UI框架介绍

    为什么要使用UI框架

    我们在开发项目中会有许多面板,比如背包面板,技能面板,设置面板等。如此多的面板我们不好统一进行管理,当需求发生更变我们需要快速的做出调整,UI框架就很好的能改善这一点,并且使代码结构更加清晰。

    UI框架如何管理

    UI框架通过核心类UIManager 1. 解析本地文档 2. 用栈统一控制面板的显示和隐藏。

    UI框架UML架构图
    UI框架.png

    二, 保存面板信息

    1. 将面板做成预制体保存在本地Resources文件夹下
    预制体.png
    2. 将面板类型及路径写入Json文件
    {
    "infoList":
    [
    {"panelTypeString":"ItemMessage",
    "path":"UIPanel/ItemMessagePanel"},
    
    {"panelTypeString":"Knapsack",
    "path":"UIPanel/KnapsackPanel"},
    
    {"panelTypeString":"MainMenu",
    "path":"UIPanel/MainMenuPanel"},
    
    {"panelTypeString":"Shop",
    "path":"UIPanel/ShopPanel"},
    
    {"panelTypeString":"Skill",
    "path":"UIPanel/SkillPanel"},
    
    {"panelTypeString":"System",
    "path":"UIPanel/SystemPanel"},
    
    {"panelTypeString":"Task",
    "path":"UIPanel/TaskPanel"}
    
    ]
    }
    

    三, 解析面板信息,开发配套数据模型

    通过上面操作我们已经将我们的面板保存到本地了,当我们使用的时候只需要解析本地文件并做数据存储即可。
    1. 准备我们的数据模型类UIPanelInfo,一定要标注可序列化特性哦。
    [Serializable]
    public class UIPanelInfo : ISerializationCallbackReceiver
    {
        [NonSerialized]
        //面板类型
        public UIPanelType panelType;
        public string panelTypeString;
        //面板路径
        public string path;
    
        //字符串转化枚举类型
        public void OnAfterDeserialize()
        {
            UIPanelType type = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
            panelType = type;
        }
    
        public void OnBeforeSerialize()
        {
    
        }
    }
    
    1. 解析本地文件,并存入字典方便加载,这里我将其写入核心类UIManager中。
        [Serializable]
        class UIPanelTypeJson
        {
            public List<UIPanelInfo> infoList;
        }
        //解析Json
        private void ParseUIPanelTypeJson()
        {
            panelPathDict = new Dictionary<UIPanelType, string>();
    
            TextAsset ta = Resources.Load<TextAsset>("UIPanelType");
    
            UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text);
    
            foreach (UIPanelInfo info in jsonObject.infoList)
            {
                //Debug.Log(info.panelType);
                panelPathDict.Add(info.panelType, info.path);
            }
        }
    
    小提示:在Unity 5.3中Unity开放了一个JsonUnility序列化类详情请自查API。
                        作用:    1. 目前支持Json转化为对象。
                                  2. 对象转化为Json格式字符。
    

    四,开发公共面板类BasePanel

    所有面板都有界面的显示,暂停。像我们的菜单面板还需要有暂停和继续,当其他面板显示我们可以防止用户与其他面板继续交互。当当前面板处于隐藏我们才允许菜单面板与用户继续交互。所以我们将面板都具有的共性做成一个公共的基类。
    
    public class BasePanel : MonoBehaviour
    {
        /// <summary>
        /// 界面被显示出来
        /// </summary>
        public virtual void OnEnter()
        {
    
        }
    
        /// <summary>
        /// 界面暂停
        /// </summary>
        public virtual void OnPause()
        {
    
        }
    
        /// <summary>
        /// 界面继续
        /// </summary>
        public virtual void OnResume()
        {
    
        }
    
        /// <summary>
        /// 界面不显示,退出这个界面,界面被关闭
        /// </summary>
        public virtual void OnExit()
        {
    
        }
    }
    

    五,开发UIManager核心管理类

    当你看到这里,恭喜你到了最核心的一部分了。
    1. 扩展Dictionary类获取Value,如果取不到则返回空。
    2. 准备一个字典成员用来存储路径和面板实例,方便获取面板。
    3. 准备一个数据结构栈控制面板的显示和隐藏。
    4. 书写实例化面板逻辑的成员函数。
    定义一个根据面板类型得到实例化面板
      /// <summary>
        /// 根据面板类型 得到实例化的面板
        /// </summary>
        /// <returns></returns>
        private BasePanel GetPanel(UIPanelType panelType)
        {
            if (panelDict == null)
            {
                panelDict = new Dictionary<UIPanelType, BasePanel>();
            }
    
            BasePanel panel = panelDict.TryGet(panelType);
    
            if (panel == null)
            {
                //如果找不到,那么就找这个面板的prefab的路径,然后去根据prefab去实例化面板          
                string path = panelPathDict.TryGet(panelType);
                GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject;
                instPanel.transform.SetParent(CanvasTransform, false);
                panelDict.Add(panelType, instPanel.GetComponent<BasePanel>());
                return instPanel.GetComponent<BasePanel>();
            }
            else
            {
                return panel;
            }
    
        }
    
    将页面入栈,显示面板
      /// <summary>
        /// 把某个页面入栈,  把某个页面显示在界面上
        /// </summary>
        public void PushPanel(UIPanelType panelType)
        {
            if (panelStack == null)
                panelStack = new Stack<BasePanel>();
    
            //判断一下栈里面是否有页面
            if (panelStack.Count > 0)
            {
                BasePanel topPanel = panelStack.Peek();
                topPanel.OnPause();
            }
    
            BasePanel panel = GetPanel(panelType);
            Debug.Log(panel == null);
            panel.OnEnter();
            panelStack.Push(panel);
        }
    
    出栈,隐藏面板
    /// <summary>
        /// 出栈 ,把页面从界面上移除
        /// </summary>
        public void PopPanel()
        {
            if (panelStack == null)
                panelStack = new Stack<BasePanel>();
    
            if (panelStack.Count <= 0) return;
    
            //关闭栈顶页面的显示
            BasePanel topPanel = panelStack.Pop();
            topPanel.OnExit();
    
            if (panelStack.Count <= 0) return;
            BasePanel topPanel2 = panelStack.Peek();
            topPanel2.OnResume();
    
        }
    

    六,开发菜单面板类和背包类使用UIManager

    上面所述我们已经完成大部分UI框架的核心架构了,接下来根据个人项目来使用该框架,这里我将举个例子来使用UI框架。

    开发菜单面板类

    我们先将我们的面板继承公共基类BasePanel,其次这里我将介绍在菜单面板类重写暂停,重启,以及Button监听事件逻辑。

     /// <summary>
        /// 界面暂停
        /// </summary>
        public override void OnPause()
        {
            canvasGroup.blocksRaycasts = false;//当弹出新的面板的时候,让主菜单面板 不再和鼠标交互
        }
    
        /// <summary>
        /// 界面重启
        /// </summary>
        public override void OnResume()
        {
            canvasGroup.blocksRaycasts = true;
        }
    
        /// <summary>
        /// 启动对应面板主要用于监听事件
        /// </summary>
        /// <param name="panelTypeString"></param>
        public void OnPushPanel(string panelTypeString)
        {
            UIPanelType panelType = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
            UIManager.Instance.PushPanel(panelType);
        }
    

    接下来我们再开发一个背包面板,来测试UI框架,这里背包面板主要重写显示和隐藏逻辑,暂停和重启逻辑与菜单面板相似。

    
        /// <summary>
        /// 显示背包
        /// </summary>
        public override void OnEnter()
        {
            if (canvasGroup == null) canvasGroup = GetComponent<CanvasGroup>();
            canvasGroup.alpha = 1;
            canvasGroup.blocksRaycasts = true;
    
            Vector3 temp = transform.localPosition;
            temp.x = 600;
            transform.localPosition = temp;
            transform.DOLocalMoveX(0, .5f);
        }
    
        /// <summary>
        /// 隐藏背包
        /// </summary>
        public override void OnExit()
        {
            //canvasGroup.alpha = 0;
            canvasGroup.blocksRaycasts = false;
    
            transform.DOLocalMoveX(600, .5f).OnComplete(() => canvasGroup.alpha = 0);
        }
    
    最后我们将菜单面板的Button注册监听事件OnPushPanel,分配面板类型字符串,即可开启测试。

    七. 结束

    感谢观看,希望这篇文章对你真正有所感悟。

    相关文章

      网友评论

      本文标题:UI框架-UIManager

      本文链接:https://www.haomeiwen.com/subject/htaqpftx.html