在说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()); } } }