UI框架搭建DAY1
阿新 • • 發佈:2018-12-29
分析:UI框架主要是為了使用者(使用框架的程式猿)更快捷、方便地開發UI,UI框架的好處還在於解耦,使得程式更具有靈活性。
UI框架的核心是視窗的管理,視窗管理的主要任務就是顯示視窗和關閉視窗。
因為視窗的型別多樣,比如彈出式視窗,固定位置視窗,隱藏其他視窗(開啟這個視窗會覆蓋整個螢幕),模態視窗等等。
這裡我目前把視窗分為三大型別:普通視窗、彈出式視窗、隱藏其他視窗,而位置固定、是否模態作為視窗的屬性。
1.為了更易於複用和拓展,我設計了一個基類BasePanel, NormalPanel, PopupPanel, HiderOtherPanel都由此基類派生。
BasePanel封裝了3個重要方法:Open(), Close(), Freeze()。
2.巧婦難為無米之炊,要顯示這些窗體首先要製作這些窗體的預製體,然後載入。為此,我又設計了一個核心類PanelManager。
PanelManager主要負責窗體的建立和銷燬(隱藏),核心方法CreatePanel()。另外使用了物件池技術,快取窗體。
3.要動態載入窗體,必須獲得窗體資源的路徑,為此我設計了一個SysDefine類,此檔案用於定義一些預製體路徑常量,節點(Inspector面板中的物體位置)常量。(後期重構時打算用Json檔案配置)。載入資源的類ResourceManager。
4.此外,我還設計了一個幫助類Helper,目前實現的功能僅僅是自動化設定窗體節點的父節點。
下面,展示我今天下午的成果。
1 using UnityEngine; 2 3 public class BasePanel : MonoBehaviour 4 { 5 //窗體型別 6 public EPanelType panelType; 7 //是否是模態視窗 8 public bool isModal; 9 //是否是固定位置視窗 10 public bool isFixed; 11 //透明度 12 ETransparencyLevel transLevel; 13 14 15 //初始化 16 privatevoid Awake() 17 { 18 panelType = EPanelType.Normal; 19 isModal = true; 20 isFixed = false; 21 transLevel = ETransparencyLevel.Opaque; 22 } 23 24 private void Start() 25 { 26 //自動設定物體的父節點 27 Helper.GetInstance().SetParent(gameObject); 28 29 } 30 31 //開啟視窗 32 public void Open() 33 { 34 gameObject.SetActive(true); 35 } 36 //關閉視窗 37 public void Close() 38 { 39 gameObject.SetActive(false); 40 } 41 //凍結視窗 42 public void Freeze() 43 { 44 //TO DO 45 } 46 }
1 using System.Collections.Generic; 2 using UnityEngine; 3 public class PanelManager 4 { 5 //本類例項 6 private static PanelManager _instance; 7 //儲存面板名字和對應的路徑字典 8 public static Dictionary<string, string> dictPanelPath; 9 //儲存已顯示的面板字典 10 public static Dictionary<string, BasePanel> dictCurPanel; 11 //儲存已隱藏的面板字典 12 public static Dictionary<string, BasePanel> dictHidePanel; 13 //儲存Popup型別面板的字典 14 public static Dictionary<string, Stack<BasePanel>> dictPopupPanel; 15 16 //單例模式 17 private PanelManager() { } 18 public static PanelManager GetInstance() 19 { 20 if(_instance == null) 21 { 22 _instance = new PanelManager(); 23 24 InitProperties(); 25 } 26 return _instance; 27 } 28 //初始化欄位 29 private static void InitProperties() 30 { 31 dictPanelPath = new Dictionary<string, string>(); 32 dictCurPanel = new Dictionary<string, BasePanel>(); 33 dictHidePanel = new Dictionary<string, BasePanel>(); 34 dictPopupPanel = new Dictionary<string, Stack<BasePanel>>(); 35 } 36 /// <summary> 37 /// 建立一個面板 38 /// 先檢查dictHidePanel集合裡是否存在此面板,有則取出顯示並加入dictCurPanel集合 39 /// 沒有,則建立一個,然後加如dictCurPanel集合。 40 /// </summary> 41 /// <param name="panelName">要建立的面板的名字</param> 42 /// <returns></returns> 43 public BasePanel CreatePanel(string panelName) 44 { 45 BasePanel basePanel = null; 46 dictHidePanel.TryGetValue(panelName, out basePanel); 47 if(basePanel != null) 48 { 49 return basePanel; 50 } 51 else 52 { 53 //建立面板 54 GameObject go = ResourceManager.GetInstance().LoadAsset<GameObject>(panelName); 55 if(go != null) 56 { 57 basePanel = go.GetComponent<BasePanel>(); 58 if(basePanel != null) 59 { 60 //新增到正在顯示的面板集合 61 dictCurPanel.Add(panelName, basePanel); 62 } 63 else 64 { 65 Debug.LogError(GetType()+"你可能忘記掛在了BasePanel型別的指令碼"); 66 } 67 return basePanel; 68 } 69 else 70 { 71 Debug.Log(GetType()+"panelName可能不存在"); 72 73 } 74 } 75 return null; 76 } 77 78 }
1 using UnityEngine; 2 3 public class ResourceManager 4 { 5 private static ResourceManager _instance; 6 public static ResourceManager GetInstance() 7 { 8 if (_instance == null) 9 { 10 _instance = new ResourceManager(); 11 } 12 return _instance; 13 } 14 private ResourceManager() { } 15 16 public T LoadAsset<T>(string path)where T:Object 17 { 18 Object o = Resources.Load(path); 19 //例項化 20 GameObject go = GameObject.Instantiate(o) as GameObject; 21 22 return go as T; 23 } 24 25 }
1 public enum ETransparencyLevel 2 { 3 Opaque, //不透明 4 Translucence, //半透明的 5 Transparent, //透明的 6 } 7 public enum EPanelType 8 { 9 Normal, 10 Popup, 11 HideOther 12 } 13 public class PrefabPathStr 14 { 15 public const string uiRootPath = @"Prefabs/UIRoot"; 16 public const string logOnPanelPath = @"Prefabs/LogOnPanel"; 17 } 18 public class NodePathStr 19 { 20 public const string normalPath = @"UIRoot/Normal"; 21 public const string popupPath = @"UIRoot/Popup"; 22 public const string hiderOtherPath = @"UIRoot/HideOther"; 23 } 24 25 26 27 public class SysDefine 28 { 29 }
1 using UnityEngine; 2 3 public class Helper 4 { 5 private static Helper _instance = null; //本類實; 6 private static Transform normal; //normal 節點 7 private static Transform popup; //popup 節點 8 private static Transform hiderOther; //hiderOther 節點 9 10 11 //單利模式 12 public static Helper GetInstance() 13 { 14 if(_instance == null) 15 { //本類例項化時,初始化節點欄位 16 normal = GameObject.Find(NodePathStr.normalPath).transform; 17 popup = GameObject.Find(NodePathStr.popupPath).transform; 18 hiderOther = GameObject.Find(NodePathStr.hiderOtherPath).transform; 19 _instance = new Helper(); 20 } 21 return _instance; 22 } 23 private Helper() { } 24 /// <summary> 25 /// 若使用者自定義了parent則使用,若沒有則根據panelType自動設定。 26 /// </summary> 27 /// <param name="child">子物體</param> 28 /// <param name="parent">父物體</param> 29 public void SetParent(GameObject child, Transform parent = null) 30 { 31 if(parent != null) 32 { 33 child.transform.SetParent(parent, true); 34 child.transform.localScale = new Vector3(1, 1, 1); 35 child.transform.localPosition = Vector3.zero; 36 } 37 else 38 { 39 if(child.GetComponent<BasePanel>()!= null) 40 { 41 EPanelType panelType = child.GetComponent<BasePanel>().panelType; 42 switch (panelType) 43 { 44 case EPanelType.Normal: 45 child.transform.SetParent(normal); 46 break; 47 case EPanelType.Popup: 48 child.transform.SetParent(popup); 49 break; 50 case EPanelType.HideOther: 51 child.transform.SetParent(hiderOther); 52 break; 53 default: 54 Debug.LogError("錯誤,未知的窗體型別"); 55 break; 56 } 57 child.transform.localScale = new Vector3(1, 1, 1); 58 child.transform.localPosition = Vector3.zero; 59 } 60 else 61 { 62 Debug.LogError(GetType()+ "請檢查此物體是否掛載了BasePanel型別指令碼!"); 63 } 64 65 } 66 } 67 }
啟動框架類StartGame.cs
1 using UnityEngine; 2 3 public class StartGame : MonoBehaviour 4 { 5 6 private GameObject uiRoot = null; 7 void Start() 8 { 9 uiRoot = GameObject.FindGameObjectWithTag("UIRoot"); 10 if (uiRoot != null) //已生成UIRoot 11 { 12 Destroy(uiRoot); 13 14 } 15 //獲取UIRoot物件 16 uiRoot = ResourceManager.GetInstance().LoadAsset<GameObject>(PrefabPathStr.uiRootPath); 17 18 //修改克隆體的名字 19 uiRoot.name = "UIRoot"; 20 //載入場景時不銷燬UIRoot 21 DontDestroyOnLoad(uiRoot); 22 23 //載入登陸面板 24 PanelManager.GetInstance().CreatePanel(PrefabPathStr.logOnPanelPath); 25 26 } 27 28 }
測試程式碼LogOnPanel.cs
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class LogOnPanel : BasePanel 6 { 7 private void Awake() 8 { 9 this.panelType = EPanelType.Normal; 10 } 11 12 }
UIRoot預製體效果圖
LogOnPanel預製體效果圖:
執行效果圖: