当前位置:   article > 正文

Unity的UI框架_unity ui框架

unity ui框架

UI框架

UI框架的含义

含义:UI框架用于管理场景中所有的面板,负责控制面板之间的跳转

UI框架的意义

1、随着游戏系统的复杂化,UI控件越来越多,各个UI之间的直接通讯,已经UI与GameObject之间的关系会越来越复杂
2、代码耦合性会很强

UI框架的实例

1、框架面板的设计

MainMenuPanel:主菜单面板
BagPanel:背包面板
ItemMessagePanel:物品信息面板
ShopPanel:商城面板
SkillPanel:技能面板
SystemPanel:系统面板
TaskPanel:技能面板

在这里插入图片描述
我们将设计好的面板做成预制体,放在Resources的目录下。

2、Json数据的读取

UIPanelInfo.json

{
  "infoList":
  [

    {
      "panelTypeString": "ItemMessage",
      "path": "UIPanel/ItemMessagePanel"
    },

    {
      "panelTypeString": "BagPanel",
      "path": "UIPanel/BagPanel"
    },

    {
      "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"
    }

  ]
}
将所有信息作为一个infolist类的对象
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

UIPanelType

public enum UIPanelType 
{
    BagPanel,
    ItemMessage,
    MainMenu,
    Shop,
    Skill,
    System,
    Task,
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

UIManager

public class UIManager 
{
    private Dictionary<UIPanelType, string> panelPathDicr;//存储所有面板Prefab的路径,UIPanelType类型,string用于存储路径

    private UIManager()
    {
        ParseUIPanelTypeJson();//调用ParseUIPanelTypeJson方法解析Json文件
    }
    //单例化
    private static UIManager instance;

    public static UIManager GetInstance()
    {
        if (instance == null)
        {
            instance = new UIManager();
        }
        return instance;
    }

    [Serializable]
    class UIPanelTypeJson//将Json文件视作一个整体,直接将其转换为List<UIPanelInfo>
    {
        public List<UIPanelInfo> infoList;
    }



    //解析Json文件
    private void ParseUIPanelTypeJson()
    {
        panelPathDicr = new Dictionary<UIPanelType, string>();//生成一个字典
        TextAsset ta = Resources.Load<TextAsset>("UIPanelType");//加载Json文件中的UIPanelType信息

       UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text);//JsonUtility——工具类,将Json中的文件解析为对象,ta.text就是JSON信息,将JSON信息转换为UIPanelTypeJson类

        //总的意思就是将JSON文件转换为UIPanelTypeJson类,而UIPanelTypeJson类中则是List<UIPanelInfo>,并其字段infoList对应JSON文件的类名

        foreach (UIPanelInfo info in jsonObject.infoList)//遍历UIPanelInfo的数组
        {
            //Debug.Log(info.panelType);
            panelPathDicr.Add(info.panelType, info.path);//这里的info相对于生成一个jsonObject.infoList,因此info就是数组中的一个元素。
            //将对象加入到字典当中去
        }
    }
    public void Test()//测试
    {
        string path;
        panelPathDicr.TryGetValue(UIPanelType.Shop, out path);
        Debug.Log(path);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

UIPanelInfo

[Serializable]
public class UIPanelInfo:ISerializationCallbackReceiver
    
    //将UIPanelInfo进行序列化,[Serializable]标签就是运行下面字段可进行读盘和写盘,负责与Json文件向对应,读取Json的文件,传递数据,可以避免直接修改Json文件
{
    [NonSerialized]
    public UIPanelType panelType;//记录Json文件中的panelType对象

    //由于无法直接解析UIPanelType,所有使用string来接受Json数据
    public string panelTypeString;
        
    //{第一种方式转换方式。
    //    get
    //    {
    //        return panelType.ToString();
    //    }
    //    set 
    //    {
    //      UIPanelType type = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), value);
    //        panelType = type;
    //    }
    //}
    public string path;//记录path的路径字段


    //反序列化 从文本信息到对象
    public void OnAfterDeserialize()//每次反序列化后就会调用
    {
        UIPanelType type = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
                panelType = type;//将文本中的panelTypeString强制转换成UIPanelType
    }

    public void OnBeforeSerialize()//每次序列化之前调用这个方法
    {
       
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
分析:
首先
1、UIPanelType类
作为一个枚举类,用于记录各个面板,保存面板的类型
2、UIPanelType.json
这是一个Json文件,用于存储各个面板的具体信息
例如:
    "panelTypeString": "MainMenu",
    "path": "UIPanel/MainMenuPanel"
panelTypeString保存对象
path保存路径
3、UIPanelInfo
负责与Json文件向对应
    public UIPanelType panelType;//记录Json文件中的panelType对象
    public string path;//记录path的路径字段

这里要将其设置为可序列化的状态[Serializable],让这个类可以读盘与写盘,方便后期对信息进行修改
,也可以避免直接修改Json文件
4、UIManger
是UI框架的核心,负责管理各种框架
第一步,将其设置为单例模式
第二步,将Json文件解析
第三步,使用UIPanelInfo的数组来接受Json文件的信息
第四步,遍历UIPanelInfo数组,并将其中的数据加入字典当中

其中有两个关键点。
第一,加载Json文件,并将文件解析为UIPanelInfo对象的数组
第二,遍历数组,并加入字典中,方便以后对其数据进行各种操作


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

3、框架逻辑设计

在这里插入图片描述
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()
    { }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

BagPanel继承BasePanel

public class BagPanel:BasePanel
{
    private CanvasGroup canvasGroup;
    private void Start()
    {
        if (canvasGroup == null)
        {
            canvasGroup = GetComponent<CanvasGroup>();
        }

        
    }
    /// <summary>
    /// 处理页面的关闭
    /// </summary>
    public override void OnExit()
    {
       // canvasGroup.alpha = 0;
        canvasGroup.blocksRaycasts = false;

    
        transform.DOLocalMoveX(600, 0.5f).OnComplete(() => canvasGroup.alpha = 0);
    }
    public void OnClosePanel()
    {
        UIManager.GetInstance().PopPanel();
    }
    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, 0.5f);
    }
    public override void OnPause()
    {
        canvasGroup.blocksRaycasts = false;
    }
    public override void OnResume()
    {
        canvasGroup.blocksRaycasts = true;
    }
    public void OnItemButtonClick()
    {
        UIManager.GetInstance().PushPanel(UIPanelType.ItemMessage);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

完善后的UIManager

public class UIManager 
{
    private Transform canvasTransform;
    private Transform CanvasTransform
    {
        get 
        {
            if (canvasTransform == null)
            {
                canvasTransform = GameObject.Find("Canvas").transform;
               
            }
            return canvasTransform;
        }
  
    }

    private Dictionary<UIPanelType, string> panelPathDicr;//存储所有面板Prefab的路径,UIPanelType类型,string用于存储路径

    private Dictionary<UIPanelType, BasePanel> panelDict;//保存所有面板的游戏物体身上的BasePanel组件

    private Stack<BasePanel> panelStacks;

    /// <summary>
    /// 把某个页面入栈,触发相应方法,并显示在界面上
    /// </summary>
    public void PushPanel(UIPanelType panelType)
    {
        if (panelStacks == null)
        {
            panelStacks = new Stack<BasePanel>();
        }
        //判断一下栈里面是否有页面
        if (panelStacks.Count > 0)
        {
            BasePanel topPanel = panelStacks.Peek();
            topPanel.OnPause();
        }
        BasePanel panel = GetPanel(panelType);
        panel.OnEnter();
        panelStacks.Push(panel);
    }
    /// <summary>
    /// 出栈,把页面从界面上移除
    /// </summary>
   public void PopPanel()
    {
        if (panelStacks == null)
        {
            panelStacks = new Stack<BasePanel>();
        }
        //BasePanel panel = GetPanel(panelType);
        if (panelStacks.Count <= 0)
        {
            return;
        }
        BasePanel topPanel = panelStacks.Pop();
        topPanel.OnExit();
        if (panelStacks.Count <= 0) return;
        BasePanel topPanel2 = panelStacks.Peek();
        topPanel2.OnResume();



    }
  

    /// <summary>
    /// 根据面板类型,得到实例化的面板
    /// </summary>
    /// <returns></returns>
    public BasePanel GetPanel(UIPanelType panelType)
    {
        if (panelDict == null)
        {
            panelDict = new Dictionary<UIPanelType, BasePanel>();
        }
      
        //BasePanel panel;
        //panelDict.TryGetValue(panelType, out panel);//TODO


        BasePanel panel = panelDict.TryGet(panelType);


        if (panel == null)
        {
            //如果找不到,就找这个面板的Prefab的路径,然后去根据Prefab去实例化面板
            //string path;
            //panelPathDicr.TryGetValue(panelType, out path);

            string path = panelPathDicr.TryGet(panelType);//字典对象的值是已经决定了的,所以不需要使用泛型而dict对象就是panelPathDicr,不需要再赋值字典
            var pan = Resources.Load(path);
            GameObject instPanel = GameObject.Instantiate(pan) as GameObject;//实例化
            instPanel.transform.SetParent(CanvasTransform, false);//TODO false表示局部位置,而非全局位置
            panelDict.Add(panelType, instPanel.GetComponent<BasePanel>());
            return instPanel.GetComponent<BasePanel>();
               
        }
        else
        {
            return panel;
        }

    }


    private UIManager()
    {
        ParseUIPanelTypeJson();//调用ParseUIPanelTypeJson方法解析Json文件
    }
    //单例化
    private static UIManager instance;

    public static UIManager GetInstance()
    {
        if (instance == null)
        {
            instance = new UIManager();
        }
        return instance;
    }

    [Serializable]
    class UIPanelTypeJson//将Json文件视作一个整体,直接将其转换为List<UIPanelInfo>
    {
        public List<UIPanelInfo> infoList;
    }



    //解析Json文件
    private void ParseUIPanelTypeJson()
    {
        panelPathDicr = new Dictionary<UIPanelType, string>();//生成一个字典
        TextAsset ta = Resources.Load<TextAsset>("UIPanelType");//加载Json文件中的UIPanelType信息

       UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text);//JsonUtility——工具类,将Json中的文件解析为对象,ta.text就是JSON信息,将JSON信息转换为UIPanelTypeJson类

        //总的意思就是将JSON文件转换为UIPanelTypeJson类,而UIPanelTypeJson类中则是List<UIPanelInfo>,并其字段infoList对应JSON文件的类名

        foreach (UIPanelInfo info in jsonObject.infoList)//遍历UIPanelInfo的数组
        {
            //Debug.Log(info.panelType);
            panelPathDicr.Add(info.panelType, info.path);//这里的info相对于生成一个jsonObject.infoList,因此info就是数组中的一个元素。
            //将对象加入到字典当中去
        }
    }
    public void Test()//测试
    {
        string path;
        panelPathDicr.TryGetValue(UIPanelType.Shop, out path);
        Debug.Log(path);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
分析
1、BasePanel作为基类被其他的具体类继承
而BasePanel中的方法为

 OnEnter()——进入
 OnPause()——暂停
 OnResume()——恢复
 OnExit()——退出
 
 2、具体的类在继承的基础上,进行具体的修改,添加事件
 3、UIManager则负责使用“栈”来对不同页面进行管理
   

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/761582
推荐阅读
相关标签
  

闽ICP备14008679号