简单的UI框架
开发UIManager的单例和JsonUtlity调试
一、UIManager的单例
首先我们要知道什么是单例模式?
单例模式是比较常见的一种设计模式,目的是保证一个类只能有一个实例,而且自行实例化并向整个系统提供这个实例,避免频繁创建对象,节约内存。
单例模式的核心:
1、定义一个静态的对象,在外部访问,在内部构造。
2、构造方法私有化。
private static UIManager _instance;
public static UIManager Instance
{
get
{
if (_instance == null)
{
_instance = new UIManager();
}
return _instance;
}
}
标准的单例模式为上述代码,我们试着分析一下!
首先建立一个私有的静态变量 _instance。
这个变量什么时候赋值呢,这时候我们定义一个get方法。
当变量为空的时候我们就创建一个。
private UIManager()
{
ParseUITypeJson();
}
UIManager是一个私有的构造方法,他只能在类的内部调用,所以在这里是可以构造的。
这样的话我们在外界只需要访问这个静态的方法就可以。
当我们第一次访问这个静态方法的时候,这个变量是为空的,这样他就会创建这个UIManager。
这样在外界我们只需要UIManager.Instance就可以访问了,当我们在外面访问的时候,它就会自动构造访问ParseUITypeJson方法,就会去解析我们的Json文件。
这里面我们测试一下,我们建立一个测试方法:
public void Test()
{
string path;
panelPathDict.TryGetValue(UIType.Knapsack, out path);
Debug.Log(path);
}
然后我们新建一个脚本来调用这个方法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameRoot : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
UIManager.Instance.Test();
}
}
当我们通过UIManager访问这个Instance时,他就会执行Get方法,他就会调用UIManager方法,就会调用ParseUITypeJson方法自动解析Json文件,然后再调用Text方法的时候就会直接输出里面的信息。
我们回到Unity中运行一下
发现控制面板报错
发现是Json文件解析的时候出现错误,那我们接下来对JsonUtility进行调试。
二、JsonUtlity调试
既然我们的Json解析不了这个类型的,那么我们就不要让他解析了。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class UIPanelInfo
{
[NonSerialized]
public UIType panelType;
public string path;
}
**[NonSerialized]**表示不去解析。
不去解析怎么办,我们就把他变成字符串类型的通过get set方法使用。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class UIPanelInfo
{
[NonSerialized]
public UIType panelType;
public string panelTypeString
{
get
{
return panelType.ToString();
}
set
{
UIType type = (UIType)System.Enum.Parse(typeof(UIType), value);
panelType = type;
}
}
public string path;
}
把Json文件中的panelType全部改成panelTypeString。
现在只有
public string panelTypeString
public string path;
实现序列话和反序列化的过程。
我们怎么样字符串转化成枚举类型,我只需要这个类每次解析完之后转化一下即可。
我们就需要给他一个get set方法,get方法用来序列化,set方法用来反序列化。
序列化的时候我们只需要取值所以只需要return就可以了。
set方法我们需要把这个值转化为UIType类型的。
这里我们用要System.Enum中的Parse方法,Parse方法可以用来转换一个特点的类型,typeof我们需要取到要转化的类型,value就代表字符串,就是我们要转化的值。
枚举类型我们不能用as UIType来转换类型,我们就只能使用强制转换。
再运行的时候我们发现还是报错,那么我们使用另一种方式!
让我们的UIPanelType继承与一个接口
public class UIPanelInfo : ISerializationCallbackReceiver
Unity无法自动序列化Dictionary数据结构,解决思路是,我们将Dictionary的数据存储在可以序列化的结构里(如List),然后通过Dictionary与可序列化结构的互操作,来完成Dictionary的存储与加载,而这个互操作的时机,就是ISerializationCallbackReceiver接口的实现。
这个接口会自带两个构造方法:
public void OnAfterDeserialize()
{
throw new NotImplementedException();
}
public void OnBeforeSerialize()
{
throw new NotImplementedException();
}
第一个构造方法时反序列化之后调用这个方法。
第二个构造方法时序列化之前调用这个方法。
反序列化是指从文本信息到对象的过程。序列化与之相反。
我们每次要序列化的时候先把属性先更改一下调用OnBeforeSerialize(),
序列化完成之后我们把文本转化成我们想要的枚举类型调用OnAfterDeserialize()。
所以我们只需要将两个构造方法改成:
public void OnAfterDeserialize()
{
UIType type = (UIType)System.Enum.Parse(typeof(UIType), panelTypeString);
panelType = type;
}
public void OnBeforeSerialize()
{
}
将value改成panelTypeString,即我们要转化的值。
接下来我们再运行一下。
这样我们就运行成功了!
总结
今天我们学会了如何构造一个标准的单例模式,同时我们也学会了当Unity无法自动自动序列化的时候,我们可以对脚本更改的两种方法。