基於UGUI的框架


這個框架簡單易懂,上手就可以直接拿來用,主要是單例管理類,界面和界面之間的互相交流通過單例去實現,個人感覺不是很好,但是我特別喜歡他的管理層級非常分明。

之后會發一個廣播機制,結合上這套UI框架,但是本文主要是講這個框架,所以后話就后話說吧,話不多說上代碼

(一)UImanager:

以panel為編程單位,儲存管理panel和下級控件,向外提供接口方法,接收界面和控件主動往管理類里注冊,排查是否重復注冊以及最后銷毀等

注意:我在使用的時候發現還是有很多需要注意的問題的

1、UIManager必須游戲啟動第一時間啟動,整個游戲進程中不能銷毀的,可以給個空物體,然后dontdestory,再動態addcompnent加入

2、整個框架主體分為三個腳本,執行順序為 UIManager > UIBase > UIBehaviour,我在第一使用的時候發現,只要一加載界面就會報空,百思不其解,然后層層斷點發現執行順序的問題,UIBehaivour先執行了,導致找不到UIManager往里注冊,有點坑

3、因為字典存的是界面name,控件name,控件對象,在RegistGameObject函數中會進行一次篩選,key不能相同,也就意味着界面名字不能重復,同界面的控件名字不能重復,我在做交易列表時被這個搞得頭疼,一定要注意,加載完換個名字

  1 using System.Collections.Generic;
  2 using UnityEngine;
  3 
  4 public class UIManager : MonoBehaviour
  5 {
  6     Dictionary<string, Dictionary<string, GameObject>> allChild;
  7     public static UIManager Instance;
  8 
  9     private GameObject mainCanvas;
 10     public GameObject MainCanvas
 11     {
 12         get
 13         {
 14             if (mainCanvas == null)
 15             {
 16                 mainCanvas = GameObject.FindGameObjectWithTag("MainCanvas");
 17             }
 18             return mainCanvas;
 19         }
 20     }
 21 
 22     public GameObject InstantiateUIPanelGameObject(string path, string endWithName = "", Transform parent = null)
 23     {
 24         if (parent == null)
 25         {
 26             parent = MainCanvas.transform;
 27         }
 28         GameObject tmpGameObj = Instantiate(Resources.Load<GameObject>(path));
 29         tmpGameObj.name = tmpGameObj.name.Replace("(Clone)", endWithName);
 30         tmpGameObj.transform.SetParent(parent,false);
 31         return tmpGameObj;
 32     }
 33 
 34     void Awake()
 35     {
 36         allChild = new Dictionary<string, Dictionary<string, GameObject>>();
 37         Instance = this;
 38     }
 39 
 40     /// <summary>
 41     /// 可以拿到字典中已經注冊過的panel下的控件
 42     /// </summary>
 43     /// <param name="panelName"></param>
 44     /// <param name="widgeNmae"></param>
 45     /// <returns></returns>
 46     public GameObject GetGameObject(string panelName, string widgeNmae)
 47     {
 48         if (allChild.ContainsKey(panelName))
 49         {
 50             return allChild[panelName][widgeNmae];
 51         }
 52         return null;
 53     }
 54 
 55     /// <summary>
 56     /// 反注冊,當你確定不再需要這個界面的時候,沒必要浪費空間
 57     /// </summary>
 58     /// <param name="panelName"></param>
 59     /// <param name="widgeName"></param>
 60     public void UnRegistGameObject(string panelName, string widgeName)
 61     {
 62         if (allChild.ContainsKey(panelName))
 63         {
 64             if (allChild.ContainsKey(widgeName))
 65             {
 66                 allChild[panelName].Remove(widgeName);
 67             }
 68         }
 69     }
 70 
 71     /// <summary>
 72     /// 銷毀某個panel上所有控件
 73     /// </summary>
 74     /// <param name="panelName"></param>
 75     public void DestroyAllWidgeFormPanel(string panelName)
 76     {
 77         if (allChild.ContainsKey(panelName))
 78         {
 79             if (allChild[panelName] != null)
 80             {
 81                 allChild[panelName].Clear();
 82             }
 83         }
 84     }
 85 
 86     /// <summary>
 87     /// 供UIBehaviour調用,UIBehaviour每個控件都會動態掛載,並且在awake里面調用,注冊自己
 88     /// </summary>
 89     /// <param name="panelName"></param>
 90     /// <param name="widgeName"></param>
 91     /// <param name="widge"></param>
 92     public void RegistGameObject(string panelName, string widgeName, GameObject widge)
 93     {
 94         if (!allChild.ContainsKey(panelName))
 95         {
 96             allChild.Add(panelName, new Dictionary<string, GameObject>());
 97         }
 98 
 99         if (!allChild[panelName].ContainsKey(widgeName))
100         {
101             allChild[panelName].Add(widgeName, widge);
102         }
103         else
104         {
105             Debug.LogError(" has been registed => " + widgeName);
106         }
107     }
108 
109     public void CleanDic()
110     {
111         allChild.Clear();
112     }
113 }

(二)UIBase:

這是一個供界面腳本繼承的基類,前面也說次框架是以panel為編程單位的,這也就是說只要你想用這套框架,只需要在panel上掛載自己寫的腳本去控制底下的所有控件即可,但是這個腳本必須繼承UIBase

這里又存在一個硬性條件,那就是panel下,你所要寫功能的控件,對象名的結尾必須_N,這是為了動態掛腳本UIBehaivour,我想這是為了讓預設體或者AB盡量減少依賴吧

在UIBase里存着panel下所有的控件,不用再去find了,避免低效,同時在UIBase里對各種控件的回調進行了二次封裝,直接調用傳參就行,這點我很喜歡,簡單粗暴

如果有需要,也可以自己拓展封裝,底層回調在UIBehaivour封裝,UIBase進行二次封裝

  1 using UnityEngine;
  2 using UnityEngine.Events;
  3 using UnityEngine.EventSystems;
  4 using UnityEngine.UI;
  5 
  6 public class UIBase : MonoBehaviour
  7 {
  8     public Transform[] allChild;
  9 
 10     private void Awake()
 11     {
 12         // 將所有的子控件 獲取到。
 13         allChild = gameObject.GetComponentsInChildren<Transform>();
 14         for (int i = 0; i < allChild.Length; i++)
 15         {
 16             //以名字區別控件,動態掛載腳本,所以必須按規范命名
 17             if (allChild[i].name.EndsWith("_N"))
 18             {
 19                 allChild[i].gameObject.AddComponent<UIBehaviour>();
 20             }
 21         }
 22     }
 23 
 24     public virtual void OnDestroy()
 25     {
 26         UIManagerLen.Instance.DestroyAllWidgeFormPanel(transform.name);
 27     }
 28 
 29     /// <summary>
 30     ///  從UIManager里面拿子控件
 31     /// </summary>
 32     /// <param name="widgaeName"></param>
 33     /// <returns></returns>
 34     public GameObject GetGameObject(string widgaeName)
 35     {
 36         return UIManagerLen.Instance.GetGameObject(transform.name, widgaeName);
 37     }
 38 
 39     /// <summary>
 40     /// 為了拿到底層封裝
 41     /// </summary>
 42     /// <param name="widgaeName"></param>
 43     /// <returns></returns>
 44     public UIBehaviour GetBehavour(string widgaeName)
 45     {
 46         // 找對象
 47         GameObject tmpBtn = GetGameObject(widgaeName);
 48         if (tmpBtn)
 49         {
 50             // 拿到 UIBehavour
 51             UIBehaviour behavour = tmpBtn.GetComponent<UIBehaviour>();
 52             return behavour;
 53         }
 54         return null;
 55     }
 56 
 57     /// <summary>
 58     /// button
 59     /// </summary>
 60     /// <param name="widageName"></param>
 61     /// <param name="action"></param>
 62     public void AddButtonListen(string widageName, UnityAction action)
 63     {
 64         UIBehaviour behavour = GetBehavour(widageName);
 65         if (behavour)
 66         {
 67             //綁定事件
 68             behavour.AddButtonListener(action);
 69         }
 70     }
 71 
 72     /// <summary>
 73     /// slider
 74     /// </summary>
 75     /// <param name="widageName"></param>
 76     /// <param name="action"></param>
 77     public void AddSliderListen(string widageName, UnityAction<float> action)
 78     {
 79         UIBehaviour behavour = GetBehavour(widageName);
 80         if (behavour)
 81         {
 82             //綁定事件
 83             behavour.AddSliderListen(action);
 84         }
 85     }
 86 
 87 
 88     /// <summary>
 89     /// scroll view
 90     /// </summary>
 91     /// <param name="cellName"></param>
 92     /// <param name="widageName"></param>
 93     /// <param name="action"></param>
 94     public void AddScrollListen(string widageName, UnityAction<Vector2> action)
 95     {
 96         UIBehaviour behavour = GetBehavour(widageName);
 97         if (behavour)
 98         {
 99             //綁定事件
100             behavour.AddScrollListen(action);
101         }
102     }
103 
104     /// <summary>
105     /// dropdown
106     /// </summary>
107     /// <param name="widageName"></param>
108     /// <param name="action"></param>
109     public void AddDropDownListen(string widageName, UnityAction<int> action)
110     {
111         UIBehaviour behavour = GetBehavour(widageName);
112         if (behavour)
113         {
114             //綁定事件
115             behavour.AddDropDownListen(action);
116         }
117     }
118 
119     /// <summary>
120     /// toggle
121     /// </summary>
122     /// <param name="widageName"></param>
123     /// <param name="action"></param>
124     public void AddToggleListen(string widageName, UnityAction<bool> action)
125     {
126         UIBehaviour behavour = GetBehavour(widageName);
127         if (behavour)
128         {
129             //綁定事件
130             behavour.AddToggleListener(action);
131         }
132     }
133 
134 
135     /// <summary>
136     /// inputfiled
137     /// </summary>
138     /// <param name="widageName"></param>
139     /// <param name="action"></param>
140     public void AddInputListen(string widageName, UnityAction<string> action)
141     {
142         UIBehaviour behavour = GetBehavour(widageName);
143         if (behavour)
144         {
145             //綁定事件
146             behavour.AddInputEndListen(action);
147         }
148     }
149 
150 
151     /// <summary>
152     /// 文本賦值
153     /// </summary>
154     /// <param name="widageName"></param>
155     /// <param name="value"></param>
156     public void ChangeText(string widageName, string value)
157     {
158         UIBehaviour behavour = GetBehavour(widageName);
159         if (behavour)
160         {
161             //綁定事件
162             behavour.ChangeText(value);
163         }
164     }
165 
166     /// <summary>
167     /// 圖片點擊
168     /// </summary>
169     /// <param name="widageName"></param>
170     /// <param name="action"></param>
171     public void AddPointClick(string widageName, UnityAction<BaseEventData> action)
172     {
173         UIBehaviour behavour = GetBehavour(widageName);
174         if (behavour)
175         {
176             behavour.AddInterfaceLisenter(EventTriggerType.PointerClick, action);
177         }
178     }
179 
180 
181     /// <summary>
182     /// 圖片拖拽 開始,正在拖,結束
183     /// </summary>
184     /// <param name="widageName"></param>
185     /// <param name="action"></param>
186     public void AddBeginDrag(string widageName, UnityAction<BaseEventData> action)
187     {
188         UIBehaviour behavour = GetBehavour(widageName);
189         if (behavour)
190         {
191             behavour.AddInterfaceLisenter(EventTriggerType.BeginDrag, action);
192         }
193     }
194     public void AddOnDrag(string widageName, UnityAction<BaseEventData> action)
195     {
196         UIBehaviour behavour = GetBehavour(widageName);
197         if (behavour)
198         {
199             behavour.AddInterfaceLisenter(EventTriggerType.Drag, action);
200         }
201     }
202     public void AddEndDrag(string widageName, UnityAction<BaseEventData> action)
203     {
204         UIBehaviour behavour = GetBehavour(widageName);
205         if (behavour)
206         {
207             behavour.AddInterfaceLisenter(EventTriggerType.EndDrag, action);
208         }
209     }
210 
211 
212     /// <summary>
213     /// 更換圖片
214     /// </summary>
215     /// <param name="widageName"></param>
216     /// <param name="value"></param>
217     public void SetImage(string widageName, Sprite value)
218     {
219         UIBehaviour subManager = GetBehavour(widageName);
220         if (subManager)
221         {
222             subManager.GetComponent<Image>().sprite = value;
223         }
224     }
225 
226     /// <summary>
227     /// 獲取圖片
228     /// </summary>
229     /// <param name="widageName"></param>
230     /// <returns></returns>
231     public Image GetImage(string widageName)
232     {
233         UIBehaviour behavour = GetBehavour(widageName);
234         if (behavour)
235         {
236             return behavour.GetImage();
237         }
238         return null;
239     }
240 
241     /// <summary>
242     /// 拿到text組件的值
243     /// </summary>
244     /// <param name="widageName"></param>
245     /// <returns></returns>
246     public string GetText(string widageName)
247     {
248         UIBehaviour behavour = GetBehavour(widageName);
249         if (behavour)
250         {
251             return behavour.GetText();
252         }
253         return null;
254     }
255 }

(三)UIBehaivour:

這個腳本就是動態掛載各個控件上的腳本,作用只有兩個

1、向UIManager注冊,接受管理

2、底層回調封裝,供UIBase調用從而進行二次封裝后直接使用  如果需要拓展也是從這里開始

 1 using System.Collections;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 using UnityEngine.UI;
 5 using UnityEngine.Events;
 6 using UnityEngine.EventSystems;
 7 
 8 
 9 public class UIBehaviour : MonoBehaviour
10 {
11     UIBase tmpBase;
12     private void Awake()
13     {
14         tmpBase = gameObject.GetComponentInParent<UIBase>();//找到父類,也就是panel
15 
16         UIManagerLen.Instance.RegistGameObject(tmpBase.name, transform.name, gameObject);//向管理類注冊自己
17     }
18 
19     private void OnDestroy()
20     {
21         UIManagerLen.Instance.UnRegistGameObject(tmpBase.name, gameObject.name);
22     }
23 
24     #region UGUI各種控件的回調封裝
25     public void AddButtonListener(UnityAction action)//按鈕回調封裝
26     {
27         Button tmpBtn = gameObject.GetComponent<Button>();
28         if (tmpBtn) tmpBtn.onClick.AddListener(action);
29     }
30     public void AddSliderListen(UnityAction<float> action)//滾動條回調封裝
31     {
32         Slider tmpBtn = gameObject.GetComponent<Slider>();
33         if (tmpBtn) tmpBtn.onValueChanged.AddListener(action);
34     }
35     public void AddDropDownListen(UnityAction<int> action)//下拉框回調封裝
36     {
37         Dropdown tmpBtn = gameObject.GetComponent<Dropdown>();
38         if (tmpBtn) tmpBtn.onValueChanged.AddListener(action);
39     }
40     public void AddScrollListen(UnityAction<Vector2> action)//滾動框回調封裝
41     {
42         ScrollRect tmpBtn = gameObject.GetComponent<ScrollRect>();
43         if (tmpBtn) tmpBtn.onValueChanged.AddListener(action);
44     }
45     public void AddToggleListener(UnityAction<bool> action)
46     {
47         Toggle tmpToggle = gameObject.GetComponent<Toggle>();
48         if (tmpToggle) tmpToggle.onValueChanged.AddListener(action);
49     }
50     public void AddInputEndListen(UnityAction<string> action)//輸入框回調封裝
51     {
52         InputField tmpBtn = GetComponent<InputField>();
53         if (tmpBtn) tmpBtn.onEndEdit.AddListener(action);
54     }
55     public void ChangeText(string value)//改變文本的接口
56     {
57         Text tmpBtn = gameObject.GetComponent<Text>();
58         if (tmpBtn) tmpBtn.text = value;
59     }
60     public Image GetImage()//如果控件是圖片,提供獲取圖片的接口
61     {
62         Image tmpBtn = gameObject.GetComponent<Image>();
63         return tmpBtn;
64     }
65     public string GetText()//如果控件是文本,提供獲取文本的接口
66     {
67         Text tmpBtn = gameObject.GetComponent<Text>();
68         return tmpBtn.text;
69     }
70     #endregion
71 
72     /// <summary>
73     /// 用代碼動態添加接口事件
74     /// </summary>
75     /// <param name="action"></param>
76     public void AddInterfaceLisenter(EventTriggerType triger, UnityAction<BaseEventData> action)
77     {
78 
79         EventTrigger trigger = gameObject.GetComponent<EventTrigger>();
80 
81         if (trigger == null)
82             trigger = gameObject.AddComponent<EventTrigger>();
83 
84         EventTrigger.Entry entry = new EventTrigger.Entry();
85         //綁定哪個接口
86         entry.eventID = triger;
87 
88         entry.callback = new EventTrigger.TriggerEvent();
89 
90         entry.callback.AddListener(action);
91 
92         trigger.triggers.Add(entry);
93     }
94 }

(四)使用:

繼承,調用就行了,簡單示例一下

 

 

總結:

這個框架有優點,也有缺點

優點是層級管理分明,分工明確,封裝之后調用簡單方便

缺點界面和界面的交流,以及模塊和模塊之間的交流,耦合性還是不能很好的解決

有時間會寫一套廣播機制,配合着使用,已達到盡可能解耦的效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM