1.我们懂得了如何加载Json文件里的数据,那么通过加载这些数据,我们可以做很多事情,例如加载装备信息或者其他的信息,今天我们用加载出来的信息去动态加载UI面板。
步骤:
①将下面关于UI面板的东西作为预制体,放在Resources文件下,方便我们动态加载。(canvas里的东西除了EventSystem留在Canvas,其他都分别做成预制体)
②还是先创建一个json文件存放好需要的信息。结构为集合infoList里存放几个面版的类型和路径(在Resources文件下的路径)
{
"infoList":
[
{"panelTypeString":"Task",
"path":"Task"
},
{
"panelTypeString":"canvas",
"path":"Canvas"
},
{
"panelTypeString":"ItemMessage",
"path":"icon"
},
{
"panelTypeString":"MainMenu",
"path":"MainPanel"
}
]
}
注意:写完一定要去百度检验格式,避免不必要的错误。
③接着创建一个脚本UIPanelType.cs,里面只有UI面板的类型
public enum UIPanelType
{
MainMenu,
Task,
Shop,
Bag,
Skill,
System,
ItemMessage,
canvas
}
④进行反序列化(即二进制转对象),需要创建一个脚本UIPanelInfo进行操作,该脚本需要实现序列化接口ISerializationCallbackReceiver;
// 进行反序列化
[Serializable]//一定要写,而且不能错
public class UIPanelInfo:ISerializationCallbackReceiver
{
[NonSerialized]//一定要写,而且不能错
//UI的类型
public UIPanelType uiPanelType;
//下面两项与json文件里的数据要一样,顺序也要一样,例如:"panelTypeString":"Skill"的panelTypeString
//存储Json里UI的类型的字符串
public string panelTypeString;
//存储Json里UI预制体路径的字符串
public string path;
//反序列之前调用
public void OnAfterDeserialize()
{
uiPanelType=(UIPanelType )Enmu.Parse(typeof(UIPanelType ),panelTypeString);
}
//序列化之前调用该方法
public void OnBeforeSerialize()
{
}
}
在该脚本下再创一个类(UIPanelTypeJson),也可以另外创建一个脚本
[Serializable]
class UIPanelTypeJson
{
public List<UIPanelInfo> infoList;//C#中集合和json的集合名字要一致,且需要标记上上序列化
}
⑤再创建一个BasePanel脚本作为基类,让其他子类继承。
BasePanel暂时不写东西,子类也暂时不写
⑥接下来我们需要使用字典来存储各种数据,需要使用TryGetValue(),它需要传一个key值,和一个变量存储返回的信息。如果大量使用TryGetValue(),则需要创建大量的变量。所以我们要重新编写一个方法避免这种情况。需要新建一个静态类DictionaryExtend
// 扩张字典的方法
//根据Key获得value,如果得到直接返回value,得不到返回null
//this Dictionary<Tkey,Tvalue>dict表示要获取值的字典,其中dict表示的是谁来调用这个方法。
public static Tvalue TryGet<Tkey,Tvalue>(this Dictionary<Tkey,Tvalue>dict,Tkey key)
{
Tvalue value;
dict.TryGetValue(key,out value);
return value;
}
⑦接下来最重要的一个类,UIManager(管理类)负责将json数据导入,动态加载脚本等操作。
public class UIManager
{
//单例模式(防止创建多个该对象)
private static UIManager instance;
public static UIManager GetInstance
{
get
{
if(instance==null)
{
instance=new UIManager();
}
}
}
//加载Canvas面板
private GameObject canvasTransform;
public GameObject CanvasTransform
{
get
{
if(canvasTransform==null)
{
string path = pannelPathDict.TryGet(UIPanelType.canvas);
canvasTransform = GameObject.Instantiate(Resources.Load(path)) as GameObject;
canvasTransform.name = path;
}
return canvasTransform;
}
}
//存储加载进来的json数据
private Dictonary<UIPanelType,string> pannelPathDict;
//存放生成后的UI面板
private Dictionary<UIPanelType, BasePanel> panelDict;
//用栈来存放已经显示出来的UI面板
private Stack<BasePanel> panelStack;
//构造私有化
private UIManager()
{
ParseUIPanelTypeJson();
}
void ParseUIPanelTypeJson()
{
if(pannelPathDict==null)
{
pannelPathDict=new Dictionary<UIPanelType,string>();
}
//加载json文件,json文件在Resources文件中
TextAsset info=Resources.Load<TextAsset>("Json/UIPanelTypeJson");
UIPanelTypeJson jonObj=JsonUtility.Fromjson<UIPanelTypeJson>(info.text);
//将每个数据存储在字典中
foreach (UIPanelInfo item in jsonObj.infoList)
{
pannelPathDict.Add(item.uiPanelType, item.path);
}
//加载面板并且返回对应的脚本类型
BasePanel GetPanel(UIPanelType panelType)
{
//判空,若为空则创建一个对象
if(panelDict==null)
{
panelDict=new Dictionary<UIPanelType,BasePanel>();
}
//从panelDict获取脚本,获取不到则证明没有加载面板
BasePanel pannel=paneDict.TryGet(panelType);
if(pannel==null)
{
//如果pannel为空,先获得面板的路径,之后加载它
string path=panelPathDict.TryGet(panelType);
if(path!=null)
{
//生成面板
GameObject instPanel=GameObject.Instantiate(Resources.Load(path))as GameObject;
//将面板设为Canvas的子物体,才能显示出来。
instPanel.transform.SetParent(CanvasTranfrom.transform,false);
instPanel.name=path;
//为该物体添加对应的脚本
AddScriptsCompent(panelType,instpanel);
//将面板类型和脚本存放到字典中
panelDict.Add(panelType,instPanel.GetComponent<BasePanel>());
return instPanel.GetComponent<BasePanel>();
}
else
{
//路径为空,证明没有该类型的面板,返回空
return null;
}
}
else
{
//证明已经有该面板,无需再加载。
return pannel;
}
}
//动态加载脚本
void AddScriptsCompent(UIPanelType panelType,GameObject panel)
{
switch(panelType)
{
case UIPanelType.Bag:
panel.AddComponent<BagPanel>();
break;
case UIPanelType.ItemMessage:
panel.AddComponent<ItemMessagePanel>();
break;
case UIPanelType.MainMenu:
panel.AddComponent<MainMenuPanel>();
break;
case UIPanelType.Shop:
panel.AddComponent<ShopPanel>();
break;
case UIPanelType.Skill:
panel.AddComponent<SkillPanel>();
break;
case UIPanelType.System:
panel.AddComponent<SystemPanel>();
break;
case UIPanelType.Task:
panel.AddComponent<TaskPanel>();
break;
}
}
//将显示的面板压入栈中
public void PushPanel(UIPanelType uIPanelType)
{
//判空
if(panelStack==null)
{
panelStack=new Stack<BasePanel>();
}
BasePanel panel=Getpanel(uIPanelType);
//为了后面UI各种状态处理,将其压入栈
panelSatck.push(panel);
}
}
⑧在之前的BasePanel的子脚本MainMenuPanel 中添加button事件监听
//面板上要有Button组件
private Button icon;
void Start()
{
icon = GameObject.Find("Canvas/icon/TaskButton").GetComponent<Button>();
//lamda表达式调用有参函数
icon.onClick.AddListener(() =>
{
testButton(UIPanelType.Task);
});
}
//根据类型生成点击按钮后生成的面板
void testButton(UIPanelType type)
{
UIManager.GetInstacne.PushPanel(type);
}
最后创建一个脚本作为启动脚本 GameRoot
void Start()
{
UIManager.GetInstacne.PushPanel(UIPanelType.MainMenu);
UIManager.GetInstacne.PushPanel(UIPanelType.ItemMessage);
}
运行结果,点击任务后,弹出任务界面