文件准备

在Scripts文件夹内新建文件夹命名为UGUI,在UGUI文件夹内新建三个文件夹命名为Item、Panel、Window,在UGUI文件夹内新建三个脚本命名为:ItemBaseWindowBaseUIManager

在GameData——Prefabs——UGUI文件夹中新建两个文件夹:Item和Panel

UIManager

UIManager脚本内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class UIManager : SingletonPattern<UIManager>
{
private RectTransform m_UIRoot;
private RectTransform m_WndRoot;
private Camera m_UICamera;
private EventSystem m_EventSystem;
private float m_CanvasRate = 0;

private string m_UIPrefabPath = "Assets/GameData/Prefabs/UGUI/Panel/";
//注册的字典
private Dictionary<string,System.Type> m_RegisterDic = new Dictionary<string, System.Type>();

private Dictionary<string, WindowBase> m_WindowDic = new Dictionary<string, WindowBase>();
//已经打开的窗口列表,用于全部关闭
private List<WindowBase> m_WindowList = new List<WindowBase>();

/// <summary>
/// 初始化UI管理器
/// </summary>
/// <param name="uiRoot">UICanvas父节点</param>
/// <param name="wndRoot">窗口父节点</param>
/// <param name="uiCamera">UI摄像机</param>
public void Init(RectTransform uiRoot,RectTransform wndRoot,Camera uiCamera,EventSystem eventSystem)
{
m_UIRoot = uiRoot;
m_WndRoot = wndRoot;
m_UICamera = uiCamera;
m_EventSystem = eventSystem;
m_CanvasRate = Screen.height / (m_UICamera.orthographicSize * 2);

}
/// <summary>
/// 设置所有界面UI路径
/// </summary>
/// <param name="path"></param>
public void SetUIPrefabPath(string path)
{
m_UIPrefabPath = path;
}
/// <summary>
/// 窗口注册
/// </summary>
/// <typeparam name="T">窗口Type</typeparam>
/// <param name="name">窗口名</param>
public void Register<T>(string name) where T : WindowBase
{
m_RegisterDic[name] = typeof(T);
}
private T FindWindowByName<T>(string name) where T : WindowBase
{
WindowBase wnd = null;
if (m_WindowDic.TryGetValue(name, out wnd))
{
return wnd as T;
}
return null;
}
/// <summary>
/// 创建并返回窗口
/// </summary>
/// <param name="wndName">窗口名</param>
/// <param name="bTop">是否在最前</param>
/// <param name="args">各种参数</param>
/// <returns>窗口</returns>
public WindowBase CreateWindow(string wndName,bool bTop = true,bool isFromResFolder = false,params object[] args)
{
WindowBase wnd = FindWindowByName<WindowBase>(wndName);
if (wnd == null)
{
System.Type tp = null;
if (m_RegisterDic.TryGetValue(wndName, out tp))
{
wnd = System.Activator.CreateInstance(tp) as WindowBase;
}
else
{
Debug.LogError("找不到窗口对应的脚本,窗口名是:"+ wndName);
return null;
}
GameObject wndObj = null;
if (isFromResFolder)
{
wndObj = GameObject.Instantiate(Resources.Load<GameObject>(wndName.Replace(".prefab","")));
}
else
{
wndObj = ObjectPoolManager.Instance.InstantiateObject(m_UIPrefabPath + wndName,false,false);
}
if (wndObj == null)
{
Debug.Log("创建窗口失败,请检查Prefab或其路径,WindowName:" + wndName);
return null;
}
if (!m_WindowDic.ContainsKey(wndName))
{
m_WindowList.Add(wnd);
m_WindowDic.Add(wndName, wnd);
}

wnd.GameObject = wndObj;
wnd.Transform = wndObj.transform;
wnd.Name = wndName;
wnd.OnAwake(args);
wnd.IsFromResFolder = isFromResFolder;
wndObj.transform.SetParent(m_WndRoot, false);

if(bTop)
{
wndObj.transform.SetAsLastSibling();
}

wnd.OnEnable(args);
}
else
{
EnableWnd(wndName,bTop,args);
}
return wnd;
}
/// <summary>
/// 根据窗口名字显示窗口
/// </summary>
/// <param name="wndName">窗口名字</param>
/// <param name="args">窗口参数</param>
public void EnableWnd(string wndName,bool bTop = true, params object[] args)
{
WindowBase wnd = FindWindowByName<WindowBase>(wndName);
EnableWnd(wnd,bTop, args);
}
/// <summary>
/// 根据窗口对象显示窗口
/// </summary>
/// <param name="wnd">窗口对象</param>
/// <param name="args">窗口参数</param>
public void EnableWnd(WindowBase wnd,bool bTop = true, params object[] args)
{
if (wnd != null)
{
if(wnd.GameObject != null && !wnd.GameObject.activeSelf)
{
wnd.GameObject.SetActive(true);
}
if (bTop)
{
wnd.Transform.SetAsLastSibling();
}
wnd.OnEnable(args);
}
}
/// <summary>
/// 根据名字隐藏窗口
/// </summary>
public void DisableWnd(string wndName)
{
WindowBase wnd = FindWindowByName<WindowBase>(wndName);
DisableWnd(wnd);
}
/// <summary>
/// 根据窗口对象隐藏窗口
/// </summary>
public void DisableWnd(WindowBase wnd)
{
if (wnd != null)
{
wnd.GameObject.SetActive(false);
wnd.OnDisable();

}
}
/// <summary>
/// 显示或隐藏所有UI
/// </summary>
public void EnOrDisableAllUI(bool isEnable)
{
if (m_UIRoot != null)
{
m_UIRoot.gameObject.SetActive(isEnable);
}
}
/// <summary>
/// 设置默认选择对象,一般用于PC
/// </summary>
public void SetDefaultSelectObj(GameObject obj)
{
if (m_EventSystem != null)
{
m_EventSystem = EventSystem.current;
}
m_EventSystem.firstSelectedGameObject = obj;
}
/// <summary>
/// 所有已打开窗口的更新
/// </summary>
public void OnUpdate()
{
for (int i = 0; i < m_WindowList.Count; i++)
{
if (m_WindowList[i] != null)
{
m_WindowList[i].OnUpdate();
}
}
}
/// <summary>
/// 发送消息给窗口
/// </summary>
/// <param name="name">窗口名</param>
/// <param name="msgID">消息ID</param>
/// <param name="args">参数数组</param>
/// <returns></returns>
public bool SendMessageToWnd(string name, UIMsgID msgID = 0, params object[] args)
{
WindowBase wnd = FindWindowByName<WindowBase>(name);
if (wnd != null)
{
return wnd.OnMessage(msgID, args);
}
return false;
}
/// <summary>
/// 根据窗口名关闭窗口
/// </summary>
/// <param name="name">窗口名</param>
/// <param name="destroy">是否完全销毁</param>
public void CloseWnd(string name, bool destroy = false)
{
WindowBase wnd = FindWindowByName<WindowBase>(name);
CloseWnd(wnd,destroy);
}
/// <summary>
/// 根据窗口对象关闭窗口
/// </summary>
/// <param name="wnd">窗口对象</param>
/// <param name="destroy">是否完全销毁</param>
public void CloseWnd(WindowBase wnd, bool destroy = false)
{
if( wnd != null )
{
wnd.OnDisable();
wnd.OnClose();
if(m_WindowDic.ContainsKey(wnd.Name))
{
m_WindowDic.Remove(wnd.Name);
m_WindowList.Remove(wnd);
}
if (!wnd.IsFromResFolder)
{
if (destroy)
{
ObjectPoolManager.Instance.ReleaseObject(wnd.GameObject, 0, true);
}
else
{
ObjectPoolManager.Instance.ReleaseObject(wnd.GameObject, hasRecycleParent: false);
}
}
else
{
GameObject.Destroy(wnd.GameObject);
}
wnd.GameObject = null;
wnd = null;
}
}
/// <summary>
/// 关闭所有窗口,不销毁窗口
/// </summary>
public void CloseAllWnd()
{
for (int i = m_WindowList.Count - 1; i >= 0; i--)
{
CloseWnd(m_WindowList[i]);
}
}
/// <summary>
/// 切换到唯一窗口
/// </summary>
public void SwitchStateByName(string name, bool bTop = true,bool isFromResFolder = false, params object[] args)
{
CloseAllWnd();
CreateWindow(name, bTop,isFromResFolder, args);
}
}
public enum UIMsgID
{
None = 0,
}

WindowBase

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class WindowBase
{
/// <summary>
/// 引用GameObject
/// </summary>
public GameObject GameObject { get; set; }
/// <summary>
/// 引用Transform
/// </summary>
public Transform Transform { get; set; }
/// <summary>
/// 窗口名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 是否从Resource文件夹加载
/// </summary>
public bool IsFromResFolder { get; set; } = false;

protected List<Button> m_AllButton = new List<Button>();
protected List<Toggle> m_AllToggle = new List<Toggle>();

public virtual bool OnMessage(UIMsgID msgID,params object[] args) { return true; }
public virtual void OnAwake(params object[] args) { }
public virtual void OnEnable(params object[] args) { }
public virtual void OnDisable() { }
public virtual void OnUpdate() { }
public virtual void OnClose()
{
RemoveAllButtonListeners();
RemoveAllToggleListeners();
m_AllButton.Clear();
m_AllToggle.Clear();
}
/// <summary>
/// 同步替换图片
/// </summary>
/// <param name="spritePath">图片路径</param>
/// <param name="image">Image组件</param>
/// <param name="setNativeSize">是否保持宽高比</param>
/// <returns>是否成功替换图片</returns>
public bool ChangeImageSprite(string spritePath,Image image,bool setNativeSize = false)
{
if (image == null)
{
return false;
}
Sprite sp = ResourceManager.Instance.LoadResource<Sprite>(spritePath);
if(sp != null)
{
if (image.sprite != null)
image.sprite = null;
image.sprite = sp;
if(setNativeSize)
{
image.SetNativeSize();
}
return true;
}
return false;
}
/// <summary>
/// 异步替换图片
/// </summary>
/// <param name="spritePath">图片路径</param>
/// <param name="image">Image组件</param>
/// <param name="setNativeSize">是否保持宽高比</param>
public void ChangeImageSpriteAsync(string spritePath, Image image, bool setNativeSize = false)
{
if (image == null)
{
return;
}
ResourceManager.Instance.AsyncLoadResource(spritePath,OnLoadSpriteFinish,LoadResPriority.RES_MIDDLE,image,setNativeSize);
}
void OnLoadSpriteFinish(string path,Object obj,object param1 = null,object param2 = null,object param3 = null)
{
if(obj!=null)
{
Sprite sp = obj as Sprite;
Image image = param1 as Image;
bool setNativeSize = (bool)param2;
if (image.sprite != null)
image.sprite = null;
image.sprite = sp;
if(setNativeSize)
{
image.SetNativeSize();
}
}
}
/// <summary>
/// 移除所有Button事件
/// </summary>
protected void RemoveAllButtonListeners()
{
m_AllButton.ForEach(btn =>
{
btn.onClick.RemoveAllListeners();
});
}
/// <summary>
/// 移除所有Toggle事件
/// </summary>
protected void RemoveAllToggleListeners()
{
m_AllToggle.ForEach(toggle =>
{
toggle.onValueChanged.RemoveAllListeners();
});
}
/// <summary>
/// 添加Button事件监听
/// </summary>
public void AddButtonClickListener(Button btn,UnityEngine.Events.UnityAction action)
{
if(btn != null)
{
if (!m_AllButton.Contains(btn))
{
m_AllButton.Add(btn);
}
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(action);
btn.onClick.AddListener(BtnPlaySound);
}
}
/// <summary>
/// 添加Toggle事件监听
/// </summary>
public void AddToggleClickListener(Toggle toggle, UnityEngine.Events.UnityAction<bool> action)
{
if (toggle != null)
{
if (!m_AllToggle.Contains(toggle))
{
m_AllToggle.Add(toggle);
}
toggle.onValueChanged.RemoveAllListeners();
toggle.onValueChanged.AddListener(action);
toggle.onValueChanged.AddListener(TogglePlaySound);
}
}
protected void BtnPlaySound()
{

}
protected void TogglePlaySound(bool isOn)
{

}
}

ItemBase

主要用于弹窗类,经常load的小UI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using UnityEngine.UI;

public class ItemBase : MonoBehaviour
{
/// <summary>
/// 添加Button事件监听
/// </summary>
public void AddButtonClickListener(Button btn, UnityEngine.Events.UnityAction action)
{
if (btn != null)
{
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(action);
btn.onClick.AddListener(BtnPlaySound);
}
}
/// <summary>
/// 添加Toggle事件监听
/// </summary>
public void AddToggleClickListener(Toggle toggle, UnityEngine.Events.UnityAction<bool> action)
{
if (toggle != null)
{
toggle.onValueChanged.RemoveAllListeners();
toggle.onValueChanged.AddListener(action);
toggle.onValueChanged.AddListener(TogglePlaySound);
}
}
protected void BtnPlaySound()
{

}
protected void TogglePlaySound(bool isOn)
{

}
}