UIFramwork(Unity3D)
目标:UIFramewrok教程学习笔记
知识点:
1 图片导入后要把Texture Type修改为Sprite(2D and UI)。
2 画布的Canvas Scaler(Script)组件中的UI Scale Mode属性改为Scale With Screen Size,Match属性改为1,对应Height,这样画布就能自适应屏幕大小。
序列化 : 目的是以某种存储形式使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。简单来说就是将对象保存到文件中(比如Unity中的场景文件和预制体默认就是以二进制文件保存在工程目录)
Unity序列化
- SerializeField:表示变量可被序列化。与private、protected结合使用可以达到让脚本的变量在检视面板里可视化编辑,同时保持它的私有性的目的。
- HideInInspector:将原本显示在检视面板上的序列化值隐藏起来。
- NonSerialized:将一个公有变量不序列化并且不现实在检视面板中。
- Serializable:用在类的前面,表示该类可被序列化。
举例:
public class Test :Monobehavior
{
public int a; //序列化,显示
private int b; //不序列化,不显示
[SerializeField ] int c; //序列化,显示
[HideInInspector] public int d; //序列化,不显示
[NonSerialized ] public int e; //不序列化,不显示
public Test2 test2; //序列化,显示(可序列化的部分)
}
[Serializable ]
public class Test2
{
public int aa;
private int bb;
}
将此脚本挂在预制体下,用Sublime打开预制体可看到:
a:0
c:0
d:0
test2:
aa:0
注意:并非所有的公有变量都可以被序列化。其中const,static变量无法序列化。链表和字典在内存中的存储不连续,也无法序列化。
从文件中导入JSon对象:
using UnityEngine;
[System.Serializable]
public class PlayerInfo
{
public string name;
public int lives;
public float health;
public static PlayerInfo CreateFromJSON(string jsonString)
{
return JsonUtility.FromJson<PlayerInfo>(jsonString);
}
// Given JSON input:
// {"name":"Dr Charles","lives":3,"health":0.8}
// this example will return a PlayerInfo object with
// name == "Dr Charles", lives == 3, and health == 0.8f.
}
创建的对象必须是可序列化的,每个字段对应一个Key值(名字要一样)。由于不能直接识别Enum类型,所以先用string类型替代,在反序列化(从文本里读取到对象)之后再转换,比如:
[Serializable]
public class UIPanelInfo : ISerializationCallbackReceiver {
[NonSerialized] public UIPanelType panelType; //Enum类型不序列化
public string panelTypeString;
public string path;
//反序列化 从文本信息到对象
public void OnAfterDeserialize() //实现接口函数
{
UIPanelType type = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
panelType = type;
}
public void OnBeforeSerialize()
{
throw new NotImplementedException();
}
}
扩展Dictionary类,能直接获取每个键对应的值,不用先定义再以参数的形式获取
public static class DictionaryExtension {
public static TValue TryGet<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue = default(TValue))
{
return dict.ContainsKey(key) ? dict[key] : defaultValue;
}
}
UIFramewrok
1 为所有页面Panel创建一个基类BasePanel,抽象四个虚函数(显示,暂停,恢复,关闭)用来操作界面
public class BasePanel : MonoBehaviour {
public virtual void OnEnter() {}
public virtual void OnPause() {}
public virtual void OnResume() {}
public virtual void OnExit() {}
}
2 为每一个页面添加一个对应的枚举类型
public enum UIPanelType {
ItemMessage,
Knapsack,
MainMenu,
Shop,
Skill,
System,
Task
}
3 在JSon文件中保存每个页面的类型信息以及预制体路径
{
"panelInfoList": [
{
"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": "Task",
"path": "UIPanel/TaskPanel"
},
{
"panelTypeString": "System",
"path": "UIPanel/SystemPanel"
}
]
}
4 用单例模式创建一个管理类UIManager来管理所有界面
public class UIManager {
private Dictionary<UIPanelType, string> panelPathDict; //存储所有面板Prefab的路径
private Dictionary<UIPanelType, BasePanel> panelDict; //存储所有实例化的Panel的BasePanel组件
private Stack<BasePanel> panelStack; //存储所有的Panel来控制界面状态
private static UIManager _instance;
private Transform canvasTransform;
public Transform CanvasTransform
{
get
{
if (canvasTransform == null)
{
canvasTransform = GameObject.Find("Canvas").transform;
}
return canvasTransform;
}
}
public static UIManager Instance
{
get
{
if (_instance == null)
{
_instance = new UIManager();
}
return _instance;
}
}
private UIManager()
{
ParsePanleTypeJson();
}
public void PushPanel(UIPanelType panelType) // 显示界面接口
{
if (null == panelStack)
{
panelStack = new Stack<BasePanel>();
}
if (0 < panelStack.Count)
{
BasePanel topPanel = panelStack.Peek();
topPanel.OnPause();
}
BasePanel panel = GetPanel(panelType);
panel.OnEnter();
panelStack.Push(panel);
}
public void PopPanel(UIPanelType panelType) // 关闭界面接口
{
if (null == panelStack)
return;
if (panelStack.Count < 0)
return;
BasePanel topPanel = panelStack.Pop();
topPanel.OnExit();
if (panelStack.Count < 0)
return;
topPanel = panelStack.Peek();
topPanel.OnResume(); // 恢复上个界面的状态
}
[Serializable]
public class PanelTypeJsonList
{
public List<UIPanelInfo> panelInfoList;
}
// 读取JSon文件中所有界面的路径
private void ParsePanleTypeJson()
{
panelPathDict = new Dictionary<UIPanelType, string>();
TextAsset ta = Resources.Load<TextAsset>("UIPanelType");
PanelTypeJsonList panelList = JsonUtility.FromJson<PanelTypeJsonList>(ta.text);
foreach (UIPanelInfo info in panelList.panelInfoList)
{
panelPathDict.Add(info.panelType, info.path);
}
}
private BasePanel GetPanel(UIPanelType panelType)
{
if (panelDict == null)
{
panelDict = new Dictionary<UIPanelType, BasePanel>();
}
BasePanel panel = panelDict.TryGet(panelType);
if (null == panel)
{
string path = panelPathDict.TryGet(panelType);
GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject;
instPanel.transform.SetParent(CanvasTransform, false);
panel = instPanel.GetComponent<BasePanel>();
panelDict.Add(panelType, panel);
}
return panel;
}
}