寫在前面的話
我會先把源碼直接給出來。博主自己也不是什麼大牛,因此寫的也不是什麼很厲害的框架,只是一個很小很小的UI框架,給初學者一點入門的思路。
不少人在剛開始接觸框架的時候都會有一種感受:這NM什麼DDX啊?!徹底懵逼了有沒有?!我還沒開始寫代碼呢!怎麼就已經有這麼多代碼要看啊?!還有大部分新人都會吐槽的事情:爲何要這麼寫啊?這玩意隨便寫個腳本掛上去不是分分鐘實現功能嗎?你這繞來繞去搞毛?這個主程是否是NT?!emmmmmmmmmmm…若是你知道主程怎麼想的,你不就是主程了?
因此,初次接觸框架的話,能夠抱怨,可是請儘快冷靜下來,好好看代碼。起碼要以最快的速度會用這個框架,在慢慢去分析爲何框架要這麼寫。其實看完後你就會發現,主程寫的框架實現一個功能確實很麻煩,可是你用起來的時候卻很是方便,由於不少東西主程早早的就給你封裝在框架裏了,你只須要幹一些不動腦子的體力活就實現了需求,爽就一個字!這就是爲何要使用框架,爲何主程要彎彎繞繞的實現功能。
json
好,若是你作好了思想準備,那麼就先下載源碼,讀起來吧!這真的是一個很簡單的UI框架,內容很少。讀起來應該很容易。
UIFrame
提取碼:gt4a
canvas
那接下來咱們就開始吧!數組
初次接觸框架的讀者可能會徹底不知道從哪裏下手閱讀,那麼博主就帶着你們一塊兒看看,這個框架主要是用來解決什麼問題的。緩存
腳本文件夾結構
這個框架有五個基本文件夾,分別是:Managers,Models,UIBases,UIInterface,Utility。
怎麼樣?都是你們耳熟能詳的名字吧?那麼咱們應該先從哪裏開始閱讀呢?天然就是Utility文件夾了。
網絡
Utility文件夾下的腳本
打開這個文件夾,有以下腳本:
下面我將依次講解這幾個腳本各自負責作些什麼。
首先,咱們先看Singlton:
框架
using System; namespace UIFrame { public class Singleton<T> where T : class { private static T instance; public static T Instance { get { if (instance == null) { instance = (T)Activator.CreateInstance(typeof(T), true); } return instance; } } } }
很簡單,只有20行代碼。這個腳本只作了一件事,就是實現一個單例。特殊之處在於,這是一個單例的帶有泛型的基類,使用反射的方式搞定的單例,那麼他的做用呢?也很簡單,只要是你想要把一個腳本作成單例模式,那麼只須要繼承這個腳本,再私有化無參構造便可。文字可能解釋的不是很清楚,咱們結合代碼來看,接下來咱們來看看AssetsManager:dom
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace UIFrame { public class AssetsManager : Singleton<AssetsManager> { private AssetsManager() { assetsChace = new Dictionary<string, object>(); } /// <summary> /// 資源緩存池 /// </summary> private Dictionary<string, object> assetsChace; /// <summary> /// 獲取資源方法 /// </summary> /// <param name="assetPath">路徑</param> /// <returns>獲取到的對象</returns> public object GetAsset(string assetPath) { object asset = null; if (!assetsChace.TryGetValue(assetPath,out asset)) { asset = Resources.Load(assetPath); assetsChace.Add(assetPath, asset); } return asset; } } }
AssetsManager腳本是我用來作資源管理的腳本,那麼可能會在不少其餘地方要用到,那每次要用到我都去實例化就太麻煩了,並且也不利於資源管理,因此我把他作成單例。怎麼作?就利用上面的Singleton腳原本實現,咱們讓AssetsManager繼承Singleton,再私有化構造函數,就天然而然的完成了咱們的需求,之後再有其它腳本要實現單例,也這樣如法炮製便可。這裏就已經體現了一些些框架的威力。也能夠說是設計原則的好處。不展開了,回到正題。那麼這個腳本管理的是什麼資源呢?其實,什麼資源均可以,但咱們主要是針對UI資源進行管理,首先咱們寫了一個緩存池,用來緩存已經取過的資源用以二次利用。而後就是一個獲取資源的方法了,很簡單,就是傳過來一個資源的所在路徑,經過路徑將資源拿出來放進緩存後返回該資源,本身看看應該就能看懂。
好,那這個腳本就很少說了,咱們看下一個,JsonPanelManager:
ide
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace UIFrame { public class JsonPanelManager : Singleton<JsonPanelManager> { private JsonPanelManager() { jsonPanelDataDic = new Dictionary<int, Dictionary<string, string>>(); jsonLocalizationDic = new Dictionary<int, Dictionary<string, string[]>>(); widgetDataDic = new Dictionary<int, Dictionary<string, string>>(); ParseJsonPanel(); //ParseJsonLocalization(); ParseJsonWidget(); } /// <summary> /// json轉換的對象 /// </summary> private JsonPanelModel jsonPanelData; /// <summary> /// json轉換後的字典存儲 /// </summary> private Dictionary<int, Dictionary<string,string>> jsonPanelDataDic; /// <summary> /// json轉化後的本地化文件對象 /// </summary> private JsonLocalizationModel jsonLocalizationData; /// <summary> /// json轉換後的本地化文件字典 /// </summary> private Dictionary<int, Dictionary<string, string[]>> jsonLocalizationDic; //Widget解析後的數據 private JsonWidgetModel widgetData; //Widget解析後的數據【字典版】 private Dictionary<int, Dictionary<string, string>> widgetDataDic; /// <summary> /// json解析 /// </summary> private void ParseJsonPanel() { //獲取json文本對象 TextAsset assetText = AssetsManager.Instance.GetAsset(SystemDefaine.JsonPanelsPath) as TextAsset; //解析json jsonPanelData = JsonUtility.FromJson<JsonPanelModel>(assetText.text); for (int i = 0; i < jsonPanelData.AllData.Length; i++) { //新定義一個字典 Dictionary<string, string> crtPanelData = new Dictionary<string, string>(); //將場景ID和字典存入 jsonPanelDataDic.Add(i, crtPanelData); //將場景的全部資源路徑保存 for (int j = 0; j < jsonPanelData.AllData[i].Data.Length; j++) { crtPanelData.Add(jsonPanelData.AllData[i].Data[j].PanelName, jsonPanelData.AllData[i].Data[j].PanelPath); } } } /// <summary> /// json解析 /// </summary> private void ParseJsonLocalization() { //獲取json文本對象 TextAsset assetText = AssetsManager.Instance.GetAsset(SystemDefaine.JsonLanguages) as TextAsset; //解析json jsonLocalizationData = JsonUtility.FromJson<JsonLocalizationModel>(assetText.text); for (int i = 0; i < jsonLocalizationData.AllData.Length; i++) { //新定義一個字典 Dictionary<string, string[]> crtPanelData = new Dictionary<string, string[]>(); //將場景ID和字典存入 jsonLocalizationDic.Add(i, crtPanelData); //將場景的全部資源路徑保存 for (int j = 0; j < jsonLocalizationData.AllData[i].Data.Length; j++) { crtPanelData.Add(jsonLocalizationData.AllData[i].Data[j].ObjName, jsonLocalizationData.AllData[i].Data[j].TextLanguageText); } } } private void ParseJsonWidget() { TextAsset assetText = AssetsManager.Instance.GetAsset(SystemDefaine.JsonWidgetsPath) as TextAsset; widgetData = JsonUtility.FromJson<JsonWidgetModel>(assetText.text); for (int i = 0; i < widgetData.AllData.Length; i++) { //建立一個字典 Dictionary<string, string> crtDic = new Dictionary<string, string>(); //添加一個場景ID和一個字典 widgetDataDic.Add(i, crtDic); //遍歷當前場景內的全部Panel路徑數據 for (int j = 0; j < widgetData.AllData[i].Data.Length; j++) { //以PanelName爲Key,以PanelPath爲value進行存儲 crtDic.Add(widgetData.AllData[i].Data[j].WidgetName, widgetData.AllData[i].Data[j].WidgetPath); } } } /// <summary> /// 獲取資源路徑 /// </summary> /// <param name="panelName"></param> /// <returns></returns> public string GetAssetPath(string panelName,int sceneID) { if (!jsonPanelDataDic.ContainsKey(sceneID)) { return null; } if (!jsonPanelDataDic[sceneID].ContainsKey(panelName)) { return null; } return jsonPanelDataDic[sceneID][panelName]; } /// <summary> /// 獲取本地化語言數組 /// </summary> /// <param name="objName"></param> /// <param name="sceneID"></param> /// <returns></returns> public string[] GetLocalizationTextArray(string objName,int sceneID) { if (!jsonLocalizationDic.ContainsKey(sceneID)) { return null; } if (!jsonLocalizationDic[sceneID].ContainsKey(objName)) { return null; } return jsonLocalizationDic[sceneID][objName]; } public string GetWidgetPath(string widgetName, int sceneID) { if (!widgetDataDic.ContainsKey(sceneID)) return null; if (!widgetDataDic[sceneID].ContainsKey(widgetName)) return null; //若是都ID和Widget在字典中都存在,則直接返回 return widgetDataDic[sceneID][widgetName]; } } }
一樣的,JsonPanelManager 這個腳本咱們也繼承了單例,那麼這個腳本主要是用來作什麼的呢?很簡單,就是解析json文件,將json文件中存儲的資源路徑都給拿出來,而後再利用上一個腳本將資源拿出來放進緩存(也就是咱們本身定義的字典裏面,字典有多好用就不用我多說了吧)。至於json文件的解析,本篇博客也不贅述,都來看框架了,json解析這種東西應該沒問題吧?那這個腳本中除了獲取UI模塊資源,還寫了一個獲取UI動態元件和本地化的json解析,暫時用不到,先不說。
好,那這個文件夾就只剩最後一個腳本了,SystemDefaine:
函數
using UnityEngine; public static class SystemDefaine { public const string JsonPanelsPath = "Configuration/UIPanelConfig"; public const string JsonWidgetsPath = "Configuration/UIWidgetConfig"; public const string JsonLanguages = "Configuration/LocalizationConfig"; public enum SceneID { Login = 0, FightScene = 1 } public static string[] UIWidgetsMark = new string[] { "_F" }; }
SystemDefaine這個腳本,單純是用來保存常數的,注意,這是一個靜態類,暫時咱們只用到了最上面的json文件路徑的字符串常數。也沒什麼特殊的。其餘的用到再說。學習
UIBases文件夾
UIBases文件夾下有以下腳本:
咱們先來看UIWidgetBase:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UIInterface; namespace UIFrame { public class UIWidgetBase : UIMono { //綁定所屬的UI模塊 private UIModuleBase crtModule; //初始化UI元件 public void UIWidgetInit(UIModuleBase uIModuleBase) { crtModule = uIModuleBase; UIManager.Instance.AddWidget(crtModule.name, name, this); } private void OnDisable() { UIManager.Instance.RemoveWidget(crtModule.name, name); } } }
UIWidgetBase 是一個經過代碼添加到全部以「_F」結尾的UI元件身上的腳本組件。他繼承了UIMono,UIMono則實現了不少關於UI組件操做的接口,詳情本身去看看UIInterface文件夾,由於過於簡單,因此博主不作講解。
咱們再來看UIModuleBase:
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace UIFrame { //該腳本掛載在每一個UI模塊上,並確保擁有CanvasGroup組件 [RequireComponent(typeof(CanvasGroup))] public class UIModuleBase : MonoBehaviour { protected CanvasGroup canvasGroup; //獲取全部的子對象 private Transform[] allChild; protected virtual void Awake() { canvasGroup = GetComponent<CanvasGroup>(); //修改對象名稱(將生成的對象名稱後面的(clone)去掉) gameObject.name = gameObject.name.Remove(gameObject.name.Length - "(clone)".Length); allChild = transform.GetComponentsInChildren<Transform>(); AddUIWidgetBehaviour(); } //綁定該模塊對應的Controller protected void BindController(UIControllerBase controller) { controller.ControllerInit(this); } /// <summary> /// 找出須要添加widgetbase的腳本 /// </summary> private void AddUIWidgetBehaviour() { for (int i = 0; i < allChild.Length; i++) { for (int j = 0; j < SystemDefaine.UIWidgetsMark.Length; j++) { //全部子對象中名稱以規定字符串結尾的都添加上一個UIWidgetBase腳本。 if (allChild[i].name.EndsWith(SystemDefaine.UIWidgetsMark[j])) { AddComponetForWidget(i); } } } } /// <summary> /// 給對象添加widgetbase組件 /// </summary> /// <param name="index"></param> protected virtual void AddComponetForWidget(int index) { UIWidgetBase crtbase = allChild[index].gameObject.AddComponent<UIWidgetBase>(); crtbase.UIWidgetInit(this); } //經過UI元件名稱獲取該模塊中綁定的UI元件 public UIWidgetBase GetWidget(string widgetName) { return UIManager.Instance.GetWidget(name, widgetName); } //如下是用以模態處理的四個操做,你能夠在重寫時加入想要的模態處理效果,或者添加一些動畫之類的效果,簡單易懂,不作贅述 public virtual void OnEnter() { canvasGroup.blocksRaycasts = true; //LocalizationManager.Instance.LocalizationInit(); } public virtual void OnPurse() { canvasGroup.blocksRaycasts = false; } public virtual void OnResume() { canvasGroup.blocksRaycasts = true; } public virtual void OnExit() { canvasGroup.blocksRaycasts = false; } } }
UIModuleBase這個腳本是掛載在全部UI模塊上的。可是,不是直接掛載,而是每一個模塊本身寫一個腳本繼承這個腳本以後掛載。而且須要重寫這個腳本的awake方法。具體的解釋能夠仔細看看代碼以及註釋,不難理解。值得一提的是,必定要記得綁定相對應的Controller,否則沒法實現相關功能。
那麼最後咱們來講說UIControllerBase:
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace UIFrame { public class UIControllerBase { //綁定相應的UIModuleBase protected UIModuleBase uiModuleBase; //初始化控制器 public void ControllerInit(UIModuleBase uiModuleBase) { this.uiModuleBase = uiModuleBase; ControllerStart(); } protected virtual void ControllerStart() { } } }
UIControllerBase跟UIModuleBase 同樣,每一個UI模塊都須要寫一個自身的控制器繼承這個UIControllerBase,而後不須要掛載,由於他跟UIModuleBase 綁定在一塊兒,能夠直接調用。具體用法咱們後面說。咱們先接着看框架。
Managers文件夾
Managers文件夾下有以下腳本:
這兩個腳本纔是咱們框架的重中之重,或者說UIManager這個腳本纔是核心。
話很少說,咱們直接看這個腳本:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace UIFrame { public class UIManager : Singleton<UIManager> { private UIManager() { canvas = GameObject.Find("Canvas").transform; uiModuleBases = new Dictionary<UIType, UIModuleBase>(); uiModuleStack = new Stack<UIModuleBase>(); uiWidgetBases = new Dictionary<string, Dictionary<string, UIWidgetBase>>(); uiModuleList = new List<UIModuleBase>(); } /// <summary> /// ui模塊的棧 /// </summary> Stack<UIModuleBase> uiModuleStack; /// <summary> /// ui模塊的列表存儲 /// </summary> List<UIModuleBase> uiModuleList; /// <summary> /// 管理全部的UI模塊 /// </summary> Dictionary<UIType, UIModuleBase> uiModuleBases; /// <summary> /// 管理全部的元件 /// </summary> Dictionary<string, Dictionary<string, UIWidgetBase>> uiWidgetBases; /// <summary> /// 畫布 /// </summary> private Transform canvas; public UIModuleBase GetUIModuleByName(string panelName) { UIType type = UITypeManager.Instance.GetUiType(panelName, 0); return GetUIModule(type); } /// <summary> /// 獲取ui模塊 /// </summary> /// <param name="type"></param> /// <returns></returns> public UIModuleBase GetUIModule(UIType type) { UIModuleBase crtUIMdule = null; if (!uiModuleBases.TryGetValue(type,out crtUIMdule)) { crtUIMdule = InstantiateUIModule(AssetsManager.Instance.GetAsset(type.panelPath) as GameObject); uiModuleBases.Add(type, crtUIMdule); } else if(crtUIMdule == null) { crtUIMdule = InstantiateUIModule(AssetsManager.Instance.GetAsset(type.panelPath) as GameObject); uiModuleBases[type] = crtUIMdule; } return crtUIMdule; } /// <summary> /// 生成ui模塊對象 /// </summary> /// <param name="prefab"></param> /// <returns></returns> private UIModuleBase InstantiateUIModule(GameObject prefab) { GameObject obj = GameObject.Instantiate(prefab); obj.transform.SetParent(canvas, false); return obj.GetComponent<UIModuleBase>(); } /// <summary> /// 壓棧 /// </summary> /// <param name="panelName">模塊名稱</param> /// <param name="sceneID">場景ID</param> public void PushUI(string panelName,int sceneID) { //定義一個uitype UIType type = UITypeManager.Instance.GetUiType(panelName,sceneID); //獲取模塊 UIModuleBase crtbase = GetUIModule(type); //若是棧中已有元素 if (uiModuleStack.Count > 0) { //當前模塊暫停使用 uiModuleStack.Peek().OnPurse(); } //新模塊壓棧 uiModuleStack.Push(crtbase); //新模塊開啓 crtbase.OnEnter(); } /// <summary> /// 展現UI /// </summary> /// <param name="panelName"></param> /// <param name="sceneID"></param> public void ShowUI(string panelName,int sceneID) { //定義一個uitype UIType type = UITypeManager.Instance.GetUiType(panelName, sceneID); //獲取模塊 UIModuleBase crtbase = GetUIModule(type); //若是棧中已有元素 if (!uiModuleList.Contains(crtbase)) { //當前模塊暫停使用 uiModuleList.Add(crtbase); } //新模塊開啓 crtbase.OnEnter(); } /// <summary> /// 出棧 /// </summary> public void PopUI() { if (uiModuleStack.Count > 0) { uiModuleStack.Pop().OnExit(); } if (uiModuleStack.Count > 0) { uiModuleStack.Peek().OnResume(); } } /// <summary> /// 註冊UI模塊元件 /// </summary> /// <param name="moduleName"></param> private void RegisterUIModuleWidgets(string moduleName) { if (!uiWidgetBases.ContainsKey(moduleName)) { uiWidgetBases.Add(moduleName, new Dictionary<string, UIWidgetBase>()); } } /// <summary> /// 註銷UI模塊元件 /// </summary> /// <param name="moduleName"></param> public void UnRegisterUIModuleWidgets(string moduleName) { if (uiWidgetBases.ContainsKey(moduleName)) { uiWidgetBases.Remove(moduleName); } } /// <summary> /// 添加元件 /// </summary> /// <param name="moduleName">模塊名</param> /// <param name="widgetName">元件名</param> /// <param name="widget">元件</param> public void AddWidget(string moduleName, string widgetName, UIWidgetBase widget) { RegisterUIModuleWidgets(moduleName); if (!uiWidgetBases[moduleName].ContainsKey(widgetName)) { uiWidgetBases[moduleName].Add(widgetName, widget); } } /// <summary> /// 移除元件 /// </summary> /// <param name="moduleName"></param> /// <param name="widgetName"></param> public void RemoveWidget(string moduleName, string widgetName) { if (!uiWidgetBases.ContainsKey(moduleName)) { return; } if (!uiWidgetBases[moduleName].ContainsKey(widgetName)) { return; } uiWidgetBases[moduleName].Remove(widgetName); } /// <summary> /// 獲取元件 /// </summary> /// <param name="moduleName"></param> /// <param name="widgetName"></param> /// <returns></returns> public UIWidgetBase GetWidget(string moduleName, string widgetName) { //若是該模塊未註冊,註冊 if (!uiWidgetBases.ContainsKey(moduleName)) { RegisterUIModuleWidgets(moduleName); } UIWidgetBase widget = null; //嘗試獲取該模塊此元件並返回,沒有返回null uiWidgetBases[moduleName].TryGetValue(widgetName, out widget); return widget; } public GameObject CreateDynamicWidget(string widgetName) { string widgetPath = JsonPanelManager.Instance.GetWidgetPath(widgetName, 0); GameObject prefab = AssetsManager.Instance.GetAsset(widgetPath) as GameObject; return GameObject.Instantiate(prefab); } public GameObject CreateDynamicWidget(string widgetName, Transform parent, bool worldPosStays) { GameObject obj = CreateDynamicWidget(widgetName); obj.transform.SetParent(parent, worldPosStays); return obj; } } }
能夠這麼說,你看懂了這個腳本,那麼基本上這個框架你就看懂了六成以上。首先,這個腳本也是實現的單例。而後你會發現,咱們定義了不少容器,包括棧,集合,字典等等,個人註釋也寫得很清楚他們各自負責的是什麼。讀懂實際上是不難的,也沒有什麼複雜的語法,主要就是各個腳本之間相互跳轉可能會有一點繞。但這些看起來麻煩的操做都是爲了一件事:解耦合。不用我多說,你們也都知道解耦合對一個程序來講有多重要。這個腳本我能說的很少,由於各個模塊的跳轉須要你本身在編譯器上讀代碼的時候本身跳轉看起來更方便。
下面我寫一個簡單的框架使用過程,但願能幫你更好的理解這個框架。
使用該框架
新建兩個文件夾:
方便咱們管理個人腳本,這兩個文件夾名稱也很能說明問題,天然一個是放模塊腳本,一個是放控制器腳本的。
我寫了一個MainModule和一個MainController :
using System.Collections; using System.Collections.Generic; using UnityEngine; using UIFrame; public class MainModule : UIModuleBase { private MainController controller; protected override void Awake() { base.Awake(); controller = new MainController(); BindController(controller); } }
MainModule繼承了UIModuleBase ,並掛載在UI模塊mainPanel上面。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UIFrame; using Photon.Pun; using Hashtable = ExitGames.Client.Photon.Hashtable; public class MainController : UIControllerBase { protected override void ControllerStart() { base.ControllerStart(); MainModuleInit(); BindEvents(); } void MainModuleInit() { uiModuleBase.GetWidget("PlayerNameInputField_F").SetInputFieldText("Player" + Random.Range(101, 999)); MonoHelper.Instance.InvokeRepeat(() => { uiModuleBase.GetWidget("NetworkingState_F").SetTextText(PhotonNetwork.NetworkClientState.ToString()); }, 0, () => { return false; }); } void SetPlayerInfo() { PhotonNetwork.LocalPlayer.NickName = uiModuleBase.GetWidget("PlayerNameInputField_F").GetInputFieldText(); int teamIndex = uiModuleBase.GetWidget("BattleArrayDropdown_F").GetDropDownValue(); Hashtable table = new Hashtable(); table.Add(GameConst.TEAMINDEX, teamIndex); PhotonNetwork.LocalPlayer.SetCustomProperties(table); } void BindEvents() { uiModuleBase.GetWidget("BattleArrayDropdown_F").OnDropDownValueChange(OnDropDownValueChange); uiModuleBase.GetWidget("CreateRoomButton_F").AddOnClickListener(() => { SetPlayerInfo(); UIManager.Instance.PushUI("CreateRoomModule",0); }); uiModuleBase.GetWidget("RandomJoinRoomButton_F").AddOnClickListener(() => { SetPlayerInfo(); Hashtable hashtable = new Hashtable(); hashtable.Add("Password", "NULL"); PhotonNetwork.JoinRandomRoom(hashtable,2); //UIManager.Instance.PushUI("RoomModule", 0); }); uiModuleBase.GetWidget("RandomLobbyButton_F").AddOnClickListener(() => { SetPlayerInfo(); PhotonNetwork.JoinLobby(); //UIManager.Instance.PushUI("LobbyModule", 0); }); } void OnDropDownValueChange(int value) { if (value == 0) { uiModuleBase.GetWidget("BattleArrayDropdown_F").SetImageColor(Color.red); } else { uiModuleBase.GetWidget("BattleArrayDropdown_F").SetImageColor(Color.blue); } } }
MainController 繼承了UIControllerBase ,並與MainModule 綁定在一塊兒。經過uiModuleBase的GetWidget(string widgetName)方法能夠拿到相應的UI元件,並經過UIMono中實現的接口方法完成所要實現的需求。這裏作的是一個網絡對戰遊戲的主界面,因此實現的都是網絡相關功能。也只是一些簡單的添加點擊實現,獲取UI輸入框中的內容,更改UI輸入框中的內容,都是能夠一句話就解決,很是方便,也很是酷。
固然,咱們還須要在遊戲一開始運行的時候,先自動push出咱們的主頁面,因此還須要一個類來啓動框架。
我寫了一個Facade:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UIFrame; public class Facade : MonoBehaviour { private void Start() { UIManager.Instance.PushUI("MainModule",0); } }
這個腳本很簡單,只是將主模塊在遊戲開始運行時push出來。你也能夠有本身的想法。
總結
若是你看到了這裏,那麼恭喜你,你已經對UI框架有了一個最最最基礎的認知。這是一個很簡單的UI框架,代碼量總共也沒多少,真正的框架可比這個複雜的多,也不是一篇博客就能說得清的,若是想深刻學習,能夠去找找大牛寫的框架,本博客只作入門用,甚至都算不上。但願能對小白有些幫助。一塊兒加油吧!