在说UI系统的时候,先说一下有点关联的配置管理器,因为有着那么一个配置是ui配置,它记录了ui面板的名称对应的prefab和使用的lua文件,还有一些与其他面板的互斥信息,还有其他情况该不该显示的信息等。
public class GameTableMagr
: Singleton<GameTableMagr>
{
// 加载表格
public void LoadTable()
{
LoadTable("ui", typeof(TableUI));//TableUI
}
}在GameTableMagr加载了ui的配置文件后,在GameUIManager单例管理器中去把配置的ui解析为一个一个的UIAsset信息,它保存了配置信息和面板的GameObject和面板的Behaviour等。
public class UIAsset
{
public TableUI.UI ui = null;
public GameObject oUIObject = null;
public PanelBase panel = null;
public float timer = 0;
public AssetBundle bundle = null;
public UILuaBehaviour luaBehaviour = null;
}
public class GameUIManager
: Singleton<GameUIManager>
{
Dictionary<string, UIAsset> uiMap = new Dictionary<string, UIAsset>();
List<UIAsset> uiAllList = new List<UIAsset>();
public void InitAfterLoadData()
{
TableUI table = GameTableMagr.Get().GetTable("ui") as TableUI;
for(int i=0; i<table.uiList.Count; i++)
{
if ( i == 1 )
continue;
UIAsset asset = new UIAsset();
asset.ui = table.uiList[i];
uiMap.Add(asset.ui.name, asset);
uiAllList.Add( asset );
}
Resources.UnloadUnusedAssets();
GC.Collect();
}
}UI系统围绕这一个叫做UICmdSystem的单例管理器进行,首先是很多的命令数组,每个命令都是一个字符串,代表的是一个事件。而每一个命令都对应一个UI面板的名称,在所有资源都加载完成和配置加载完成的时候就会初始化命令信息,通过命令的事件为key,对应的面板名字对应的UIAsset为值,放置到一个列表中,多对多的关系。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class UICmd
{
public string key = string.Empty;
public string values = string.Empty;
}
public class UICmdSystem
: Singleton<UICmdSystem>
{
Hashtable cmdList = null;
Queue<UICmd> cmdQueue = null;
string [] regCmd =
{
"update_gold",
};
string[,] regUI =
{
{"update_gold", "Main"},
};
public void Initial()
{
cmdList = new Hashtable();
cmdQueue= new Queue<UICmd>();
for(int i=0; i<regCmd.Length; i++)
RegCmd(regCmd[i]);
}
public void InitAfterLoadData()
{
for(int i=0; i<regUI.GetLength(0); i++)
RegUICmd(regUI[i,0], regUI[i,1]);
}
void RegCmd(string key)
{
if(cmdList.ContainsKey(key))
return;
cmdList.Add(key, new List<UIAsset>());
}
void RegUICmd(string key, string panel)
{
if(cmdList.ContainsKey(key) == false)
{
Debug.LogError("[UICmdSystem] UICmd:" + key + ",not register!" );
return;
}
UIAsset asset = GameUIManager.Get().GetUIAsset(panel);
if(asset == null)
{
Debug.LogError("[UICmdSystem] UICmd:" + key + ",Panel:" + panel + ",not ui" );
return;
}
List<UIAsset> list = cmdList[key] as List<UIAsset>;
if(list.Contains(asset))
{
Debug.LogError("[UICmdSystem] UICmd:" + key + ",Panel:" + panel + ",has register" );
return;
}
list.Add(asset);
}
public void AddCommand(UICmd cmd)
{
if(cmd == null)
return;
if(cmdList.ContainsKey(cmd.key) == false)
return;
cmdQueue.Enqueue(cmd);
}
public void Tick()//Tick方法会在Main里面的Update方法调用
{
while(cmdQueue.Count != 0)
{
UICmd cmd = cmdQueue.Dequeue();
//Debug.LogError(cmd.key + " | " + cmd.values);
if(cmd == null)
continue;
List<UIAsset> uiAsset = cmdList[cmd.key] as List<UIAsset>;
for(int i=0; i<uiAsset.Count; i++)
{
UIAsset asset = uiAsset[i];
if(asset == null)
continue;
if ((asset.panel == null && asset.luaBehaviour == null) || asset.oUIObject == null)
continue;
if (asset.luaBehaviour != null) {
asset.luaBehaviour.HandleCommand(cmd);
}
if (asset.panel != null) {
asset.panel.HandleCommand(cmd);
}
}
}
cmdQueue.Clear();
}
public bool HaveCommand(UICmd cmd)
{
if(cmd == null)
return false;
if(cmdList.ContainsKey(cmd.key) == false)
return false;
UICmd[] cmds = cmdQueue.ToArray();
for(int i = 0; i < cmds.Length; i ++)
{
if(cmd.key == cmds[i].key)
return true;
}
return false;
}
}看上面的UICmdSystem就知道了,它当前已经知道哪些命令归哪些UI去处理了,当我们需要通知一个事件的时候,通过单例的UICmdSystem的AddCommand方法添加到列表里面,在Update里面就会取出来,找到命令key对应的UIAsset,再在里面找到脚本(UI面板),调用其的HandleCommand方法处理事件,并将UICmd传递进去,通过UICmd.values区分命令处理。
public override void ValueChange(UICmd cmd)//HandleCommand方法调用了ValueChange虚方法,用来给具体的Panel重写的
{
if (!m_isInit)
initUI();
if (cmd.key.Equals("loginselect_ver"))
{
if (cmd.values.Equals("loadLocVer"))
{
curVersion.gameObject.SetActive(true);
curVersion.text = CorResMgr.Get().locVer;
}
else if (cmd.values.Equals("update"))
{
curProgTxt.gameObject.SetActive(true);
curProgTxt.text = CorResMgr.Get().infoTxt;
progBar.gameObject.SetActive(true);
progBar.value = 0.0f;
updateProgCheck = StartCoroutine(updateProg());
}
}
}