UI框架—基於UGUI(學習筆記)
阿新 • • 發佈:2018-12-15
UI框架—基於UGUI
一、需求分析
(一)、需求分析UML圖
1、通過UIManger來自作解析json檔案。
2、UML各種關係
二、知識點
(一)、原理知識
1、單例模式
-
定義一個靜態的物件 在外界訪問 在內部構造。
-
構造方法私有化。
public static UIManager _instance; public static UIManager Instance { get { if (_instance == null) { _instance = new UIManager(); } return _instance; } }
(二)、外掛知識
1、使用DOTween外掛來製作panel出現和現實的動畫
- 匯入外掛,注意名稱空間的引入
- 其他的根據需求來製作
(三)、操作知識
1、場景的搭建
- 注意文字格式要設定為跟隨螢幕自適應而改變其大小
(四)、程式碼相關
1、編寫json資訊
-
編寫json相關資訊
-
因為使用了unity自帶的兩個json類來解析json所以要把一個整體包裝成另一個整體來讀取
-
json資訊如下
{ "infoList": [ {"panelTypeString":"ItemMessage"
2、解析json資訊
-
使用unity自帶的json解析類來解析
-
使用兩個字典來儲存Panel跟路徑
private Dictionary<UIPanelType, string> panelPathDict;//儲存所有面板的Prefab的路徑 private Dictionary<UIPanelType, BasePanel> panelDict;//儲存所有例項化面板的遊戲物體BasePanel元件 private Stack<BasePanel> panelStack; [Serializable] class UIPanelTypeJson { public List<UIPanelInfo> infoList; } /// <summary> /// 解析Json資訊 /// </summary> private void ParseUIPanelTypeJson() { panelPathDict = new Dictionary<UIPanelType, string>(); TextAsset ta = Resources.Load<TextAsset>("UIPanelType"); UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text); foreach (UIPanelInfo info in jsonObject.infoList) { panelPathDict.Add(info.panelType,info.path);//儲存讀取後的名字跟路徑 } }
- UIPanelInfo來讀取裡面的資訊
using System; using System.Collections; using UnityEngine; [Serializable] public class UIPanelInfo : ISerializationCallbackReceiver { [NonSerialized] //不進行讀取 public UIPanelType panelType; public string panelTypeString; //用來儲存讀取json裡面的地址字串 public string path; /// <summary> /// 實現介面,讀取json裡面的資訊 /// 反序列化 從文字資訊到物件 /// </summary> public void OnAfterDeserialize() { UIPanelType type = (UIPanelType) System.Enum.Parse(typeof(UIPanelType), panelTypeString); panelType = type; } public void OnBeforeSerialize() { } }
3、擴充套件Dictionary類裡面的方法
-
原理:有些類是系統定義好的不能修改其中的東西,只能對其中一些東西進行擴充套件,向現有型別“新增”方法,而不建立派生類,
-
擴充套件類和擴充套件方法都必須是static的,如果擴充套件方法該型別中定義的方法具有相同的名字,則擴充套件方法不會被呼叫
-
如果擴充套件的父型別更改了,擴充套件方法也失效
using System.Collections.Generic; /// <summary> /// 對Dictionary的擴充套件 /// 必須是靜態方法和靜態類 /// </summary> public static class DictionaryExtension { /// <summary> /// 嘗試根據key得到value,得到了的話直接返回value,沒有得到直接返回null /// this Dictionary<Tkey,Tvalue>dict 這個字典表示我們要獲取值的字典 /// </summary> /// <typeparam name="Tkey">泛型一</typeparam> /// <typeparam name="Tvalue">泛型二</typeparam> /// <param name="dict">方法物件</param> /// <param name="key">獲取的值</param> /// <returns>value的值</returns> public static Tvalue TryGet<Tkey,Tvalue>(this Dictionary<Tkey,Tvalue>dict,Tkey key) { Tvalue value; dict.TryGetValue(key, out value); return value; } }
4、通過CanvasGroup來控制panel的顯示和互動
-
裡面有一個alpha值來控制顯示和隱藏
-
BlockRaycasts 來控制能不能進行互動
private CanvasGroup canvasGroup; void Start() { if (canvasGroup == null) canvasGroup = GetComponent<CanvasGroup>(); } public override void OnEnter() { if (canvasGroup == null) canvasGroup = GetComponent<CanvasGroup>(); canvasGroup.alpha = 1; canvasGroup.blocksRaycasts = true; Vector3 temp = transform.localPosition; temp.x = 600; transform.localPosition = temp; transform.DOLocalMoveX(0, 0.5f); } public override void OnExit() { canvasGroup.blocksRaycasts = false; transform.DOLocalMoveX(600, 0.5f).OnComplete(() => canvasGroup.alpha = 0); } public override void OnPause() { canvasGroup.blocksRaycasts = false; } public override void OnResume() { canvasGroup.blocksRaycasts = true; } public void OnClosePanel() { UIManager.Instance.PopPanel(); } public void OnItemButtonClick() { UIManager.Instance.PushPanel(UIPanelType.ItemMessage); }
5、根據面板型別來例項化面板
-
例項化面板所需要的引數自行設定
// <summary> /// 根據面板型別,得到例項化的面板 /// </summary> /// <param name = "panelType" > 面板的名字 </ param > /// < returns ></ returns > public BasePanel GetPanel(UIPanelType panelType) { if (panelDict == null) { panelDict = new Dictionary<UIPanelType, BasePanel>(); } BasePanel panel = panelDict.TryGet(panelType); if (panel == null) { // 乳溝找不到,那麼就找這個面板的prefab的路徑,然後去根據prefab去例項化面板 string path = panelPathDict.TryGet(panelType); GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject; instPanel.transform.SetParent(CanvasTransform, false); panelDict.Add(panelType, instPanel.GetComponent<BasePanel>()); return instPanel.GetComponent<BasePanel>(); } else { return panel; } }
6、通過棧來控制面板的進入和移出
-
把每個panel看做是一個整體進行棧操作。需要的時候進棧,不需要的時候出棧
-
入棧和入棧
private Stack<BasePanel> panelStack; //棧用來存放panel元件 /// <summary> /// 把某個頁面入棧,把某個頁面顯示在介面上 /// </summary> /// <param name = "panelType" > 頁面的名字 </ param > public void PushPanel(UIPanelType panelType) { if (panelStack == null) panelStack = new Stack<BasePanel>(); //判斷一下棧裡面是否有頁面 if (panelStack.Count > 0) { BasePanel topPanel = panelStack.Peek(); topPanel.OnPause(); } BasePanel panel = GetPanel(panelType); panel.OnEnter(); panelStack.Push(panel); } /// <summary> /// 出棧,把頁面從頁面上面移除 /// </summary> public void PopPanel() { if (panelStack == null) panelStack = new Stack<BasePanel>(); if (panelStack.Count <= 0) return; //關閉棧頂頁面的顯示 BasePanel topPanel = panelStack.Pop(); topPanel.OnExit(); if (panelStack.Count <= 0) return; BasePanel topPanel2 = panelStack.Peek(); topPanel2.OnResume(); }
7、構建BasePanel 基類來進行面板操作
-
讓其他Panel來繼承BasePanel
-
裡面有四個方法,每個方法之間的關係不一樣,詳細檢視UML圖
三、遇到的問題
(一)、老師錯誤
1、Json解析出現報錯
-
Json檔案重複了
-
Json檔案沒有按照Unity裡面的Json解析需求來編輯
(二)、自己的錯誤
1、執行的時候發現報錯,提示Dictionary重複。
- 描述:Dictionary重複
- 原因:Json檔案不對,有重複的內容
- 解決:驗證Json檔案的正確性,在重新讀取
- 注意:以後如果還是類似問題要優先考慮是檔案讀取的問題。
2、關閉面板不能關閉,也就是不能出棧
-
描述:關閉面板不能關閉,也就是不能出棧
-
原因:有一句判斷寫錯了
if (panelStack.Count > 0) return;//錯誤程式碼 if (panelStack.Count <= 0) return; //正確程式碼
-
解決:根據出現問題檢查程式碼,步驟如下
-
先檢查按鈕點選事件看看是否正確。
-
在檢視關閉按鈕呼叫的是什麼方法
-
-
注意:寫程式碼的時候要小心一點,特別是相關
if
判斷的時候
3、點選商店報錯
- 描述:要例項化的物件是null。
- 原因:不知道
- 解決:從小製作商店Panel
- 注意:有時候找不到問題就關閉軟體,或者解除元件然後再裝上試試,或者重新制作遊戲物體看看。