《UI框架—基于Unity5.4UGUI(二)》

来源:互联网 发布:葫芦侠是什么软件 编辑:程序博客网 时间:2024/05/19 03:17

接着上一篇的介绍,这一篇就该干点实事了—上代码。但是在这之前,我先给出UI框架在Unity中的资源文件的截图,方便大家理解(其中的预制体和代码是根据上一篇博客的讲解给出):
这里写图片描述

1.存储面板类型和面板预设路径的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"}]}

2.每个面板对应的枚举如下:

using UnityEngine;using System.Collections;public enum UIPanelType{    MainMenu,    Knapsack,    Shop,    Skill,    Task,    System,    ItemMessage}

3.每个UI界面信息对应的类(也就是解析出来的Json对应的类):

using UnityEngine;using System.Collections;using System;[Serializable]public class UIPanelInfo : ISerializationCallbackReceiver{//和json文件信息对应的一个类    //不可序列化的,因为这里unity解析json文件时没办法解析枚举类型,所以下面定义了一个string类型的字段panelTypeString,用于两者的转化    [NonSerialized]    public UIPanelType panelType;//面板类型    public string panelTypeString;    public  string path;//面板所在路径    //实现ISerializationCallbackReceiver的接口, 反序列化方法,从文本信息到对象    public void OnAfterDeserialize()    {        UIPanelType type = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);//把一个字符串转化为一个枚举        panelType = type;    }    //实现接口, 序列化方法,从对象到文本信息    public void OnBeforeSerialize(){}}

4.(重点)UIManager管理各个UI面板的核心类:

using UnityEngine;using System.Collections;using System.Collections.Generic;/// <summary>/// 单例模式的核心:/// 1.只在该类内定义一个静态的对象,该对象在外界访问,在内部构造/// 2.构造函数私有化/// </summary>public class UIManager{//此类作为一个单例模式,即只有一个实例的模式    private static UIManager _instance;    public static UIManager Instance    {        get        {            if (_instance == null)            {                _instance = new UIManager();            }            return _instance;        }    }    private UIManager() //构造函数私有化(单例模式)    {        ParseUIPanelTypeJson();//构造该类时会解析Json    }    private Dictionary<UIPanelType, string> panelPathDict;//存储所有Perfab面板的路径    private Dictionary<UIPanelType, BasePanel> panelDict;//借助BasePanel脚本保存所有实例化出来的面板物体(因为BasePanel脚本被所有面板预设物体的自己的脚本所继承,所以需要的时候可以根据BasePanel脚本来实例化每一个面板对象)    private Stack<BasePanel> panelStack;//这是一个栈,用来保存实例化出来(显示出来)的面板    private Transform canvasTransform;//用来使实例化的面板归为它的子物体    private Transform CanvasTransform     {        get {            if (canvasTransform == null)            {                canvasTransform = GameObject.Find("Canvas").transform;            }            return canvasTransform;        }    }    //页面入栈,即把页面显示在界面上    public void PushPanel(UIPanelType panelType)    {        if (panelStack == null)//如果栈不存在,就实例化一个空栈        {            panelStack = new Stack<BasePanel>();        }        if (panelStack.Count > 0)        {            BasePanel topPanel = panelStack.Peek();//取出栈顶元素保存起来,但是不移除            topPanel.OnPause();//使该页面暂停,不可交互        }        BasePanel panelTemp = GetPanel(panelType);        panelTemp.OnEnter();//页面进入显示,可交互        panelStack.Push(panelTemp);    }    //页面出栈,即把页面从界面上移除    public void PopPanel()     {        if (panelStack == null)        {            panelStack = new Stack<BasePanel>();        }        if (panelStack.Count <= 0)  return;        //关闭栈顶页面的显示        BasePanel topPanel1 = panelStack.Pop();        topPanel1.OnExit();        if (panelStack.Count <= 0) return;        BasePanel topPanel2 = panelStack.Peek();        topPanel2.OnResume();//使第二个栈里的页面显示出来,并且可交互    }    [System.Serializable]    class UIPanelTypeJson //内部类里面就一个链表容器,用来配合解析    {        public List<UIPanelInfo> infoList;    }    //根据面板类型UIPanelType得到实例化的面板    private BasePanel GetPanel(UIPanelType panelType)     {        if (panelDict == null)//如果panelDict字典为空,就实例化一个空字典        {            panelDict = new Dictionary<UIPanelType, BasePanel>();        }        //BasePanel panel;        //panelDict.TryGetValue(panelType, out panel);//不为空就根据类型得到Basepanel        BasePanel panel = panelDict.TayGet(panelType);//我们扩展的Dictionary的方法,代码作用同上两行        if (panel == null)//如果得到的panel为空,那就去panelPathDict字典里面根据路径path找到,然后加载,接着实例化        {            string path = panelPathDict.TayGet(panelType);//我们扩展的Dictionary的方法            //panelPathDict.TryGetValue(panelType, out path);            GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject;//根据路径加载并实例化面板            instPanel.transform.SetParent(this.CanvasTransform,false);//设置为Canvas的子物体,false表示实例化的子物体坐标以Canvas为准            //TODO            panelDict.Add(panelType,instPanel.GetComponent<BasePanel>());            return instPanel.GetComponent<BasePanel>();        }        else        {            return panel;        }    }    //解析UIPanelType.json的信息    private void ParseUIPanelTypeJson()    {        panelPathDict = new Dictionary<UIPanelType, string>();//实例化一个字典对象        TextAsset ta = Resources.Load<TextAsset>("UIPanelType"); //获取UIPanelType.json文件的文本信息        UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text);//把UIPanel.json文本信息转化为一个内部类的对象,对象里面的链表里面对应的是每个Json信息对应的类        foreach (UIPanelInfo info in jsonObject.infoList)        {            //Debug.Log(info.panelType);            panelPathDict.Add(info.panelType, info.path);//把每一个进过json文件转化过来的类存入字典里面(键值对的形式)        }    }}

5.启动整个UI框架的类(这里只需要再启动游戏时加载主界面就好,其他界面是需要点击按钮时才会实例出来并显示):

using UnityEngine;using System.Collections;public class GameRoot : MonoBehaviour{    // Use this for initialization    void Start () {        UIManager.Instance.PushPanel(UIPanelType.MainMenu);    }}

6.BasePanel各个面板的基类(定义各个面板共有的四个状态):

using UnityEngine;using System.Collections;//所有面板的公共基类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(){}}

7.主界面:

using UnityEngine;using System.Collections;public class MainMenuPanel : BasePanel{    private CanvasGroup canvasGroup;//获取CanvasGroup组件,用于控制该面板的交互功能    void Start()     {        canvasGroup = this.GetComponent<CanvasGroup>();    }    public override void OnPause()//重写父类BasePanel的OnPause方法    {        canvasGroup.blocksRaycasts = false;//使该面板失去交互功能    }    //重写父类BasePanel的OnResume方法    public override void OnResume()    {        canvasGroup.blocksRaycasts = true;//使该面板继续交互功能    }    //点击功能模块按钮加载面板,并将其入栈    public void OnPushPanel(string panelTypeString)     {        //把一个字符串转化为对应的枚举类型        UIPanelType panelType =(UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);        UIManager.Instance.PushPanel(panelType);    }}

8.任务面板:

using UnityEngine;using System.Collections;using DG.Tweening;public class TaskPanel : BasePanel {    private CanvasGroup canvasGroup;//对该页面CanvasGroup组件的引用    void Start() {        if(canvasGroup == null) canvasGroup = this.GetComponent<CanvasGroup>();    }    //重写父类的OnEnter方法    public override void OnEnter()    {        if (canvasGroup == null) canvasGroup = this.GetComponent<CanvasGroup>();        this.canvasGroup.alpha = 0;        this.canvasGroup.blocksRaycasts = true;//使该页面可交互        canvasGroup.DOFade(1, 0.6f);//使该页面渐渐显示,1是Alpha值    }    //重写父类的OnExit方法    public override void OnExit()    {        this.canvasGroup.blocksRaycasts = false;//使该页面不可交互        canvasGroup.DOFade(0, 0.6f);//使该页面渐渐隐藏,0是Alpha值    }    //点击关闭按钮事件    public void OnClose()     {        UIManager.Instance.PopPanel();    }}

9.背包面板:

using UnityEngine;using System.Collections;using DG.Tweening;public class KnapsackPanel : BasePanel {    private CanvasGroup canvasGroup;    void Awake()     {        this.canvasGroup = this.GetComponent<CanvasGroup>();    }    public override void OnEnter()    {        this.canvasGroup.alpha = 1;        this.canvasGroup.blocksRaycasts = true;        Vector3 temp = this.transform.localPosition;        temp.x = 600;        this.transform.localPosition = temp;        this.transform.DOLocalMoveX(0, 0.6f);    }    public override void OnExit()    {        //this.canvasGroup.alpha = 0;        this.canvasGroup.blocksRaycasts = false;        this.transform.DOLocalMoveX(-600, 0.6f).OnComplete(()=>canvasGroup.alpha =0);    }    public override void OnPause()    {        this.canvasGroup.blocksRaycasts = false;    }    public override void OnResume()    {        this.canvasGroup.blocksRaycasts = true;    }    //点击关闭按钮    public void OnClose()     {        UIManager.Instance.PopPanel();    }    //点击装备,显示装备信息    public void OnItemButtonDown()     {        UIManager.Instance.PushPanel(UIPanelType.ItemMessage);    }}

10.技能面板

using UnityEngine;using System.Collections;public class SkillPanel : BasePanel {    private CanvasGroup canvasGroup;    void Awake()    {        this.canvasGroup = this.GetComponent<CanvasGroup>();    }    public override void OnEnter()    {        this.canvasGroup.alpha = 1;        this.canvasGroup.blocksRaycasts = true;    }    public override void OnExit()    {        this.canvasGroup.alpha = 0;        this.canvasGroup.blocksRaycasts = false;    }    public void OnClose()    {        UIManager.Instance.PopPanel();    }}

11.商城面板:

using UnityEngine;using System.Collections;public class ShopPanel : BasePanel {    private CanvasGroup canvasGroup;    void Awake()    {        this.canvasGroup = this.GetComponent<CanvasGroup>();    }    public override void OnEnter()    {        this.canvasGroup.alpha = 1;        this.canvasGroup.blocksRaycasts = true;    }    public override void OnExit()    {        this.canvasGroup.alpha = 0;        this.canvasGroup.blocksRaycasts = false;    }    public void OnClose()    {        UIManager.Instance.PopPanel();    }}

12.系统设置面板:

using UnityEngine;using System.Collections;public class SystemPanel : BasePanel {    private CanvasGroup canvasGroup;    void Awake()    {        this.canvasGroup = this.GetComponent<CanvasGroup>();    }    public override void OnEnter()    {        this.canvasGroup.alpha = 1;        this.canvasGroup.blocksRaycasts = true;    }    public override void OnExit()    {        this.canvasGroup.alpha = 0;        this.canvasGroup.blocksRaycasts = false;    }    public void OnClose()    {        UIManager.Instance.PopPanel();    }}

13.背包里的装备信息提示面板:

using UnityEngine;using System.Collections;using DG.Tweening;public class ItemMessagePanel : BasePanel{    private CanvasGroup canvasGroup;    void Awake()    {        this.canvasGroup = this.GetComponent<CanvasGroup>();    }    public override void OnEnter()    {        this.canvasGroup.alpha = 1;        this.canvasGroup.blocksRaycasts = true;        this.transform.localScale = Vector3.zero;        transform.DOScale(1, 0.6f);//缩放动画,1代表结束时的缩放    }    public override void OnExit()    {        //this.canvasGroup.alpha = 0;        this.canvasGroup.blocksRaycasts = false;        transform.DOScale(0, 0.6f).OnComplete(() => canvasGroup.alpha = 0);    }    public void OnClose()    {        UIManager.Instance.PopPanel();    }}

14.字典拓展类(用于拓展Dictionary类的TryGetValue( )方法,只是为了简化代码方便使用,UI框架里可有可无):

using UnityEngine;using System.Collections;using System.Collections.Generic;//对字典类的TayGetValue( )方法的扩展/// <summary>/// 尝试根据key得到value,得到返回value,否则返回null/// this Dictionary<Tkey,Tvalue> dict   这个字典表示我们要获取值value的字典/// 扩展方法规定类必须是一个静态类.里面包含的所有方法都必须是静态方法。扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。/// </summary>public static class DictionaryExtension {    public static Tvalue TayGet<Tkey,Tvalue>( this Dictionary<Tkey,Tvalue> dict,Tkey key)    {        Tvalue value;        dict.TryGetValue(key,out value);        return value;    }}

总结:该UI框架重点在于UI核心管理类(UIManager)的实现,其中使用栈先进后出,后进先出的思想实现了页面的逻辑管理。难点呢在于实现Json文本的解析。

原创粉丝点击