Unity3d:UI面板管理整合进ToLua
本文基于
https://github.com/chiuan/TTUIFramework
https://github.com/jarjin/LuaFramework_UGUI
进行的二次开发,Thanks!
需求:
1.需要一个UI面板管理器,逻辑写在lua里面,方便热更新。
2.管理器控制面板的打开(show),隐藏(Hide),销毁(Destroy),刷新(Rest)。
3.要有类似网页浏览器那样,点击后退(<---),会显示上一个页面。用到数据结构:栈(Stack),先进后出。打开顺序是线性的,点击“后退“”会线性的回退到上一层。
5.顶部固定的“后退”按钮所在面板,在上一层没的退的情况下,会Hide。
6.面板第一次打开是Instantiate,关闭是Hide,再次打开是Rest。避免频繁的 Instantiate和Destroy。我的想法是所有面板都是在切场景的时候,才全部Destroy。回收内存。
先看结果,不知道能不能吸引你继续往下看!

XPage:
1 using System;
2 using UnityEngine;
3 using System.Collections;
4 using Object = UnityEngine.Object;
5 using LuaFramework;
6
7 public enum EPageType
8 {
9 None,
10 Normal,
11 PopUp,
12 Fixed,
13 Toppest,
14 }
15
16 public enum EPageMode
17 {
18 DoNothing,
19 HideOtherOnly,
20 HideOtherAndNeedBack,
21 }
22
23 public enum EPageState
24 {
25 NONE,
26 OPEN, //打开
27 HIDE, //隐藏
28 CLOSE,//销毁
29 }
30
31 public class XPageLoadBind
32 {
33 /// <summary>
34 /// 绑定你自己的资源加载管理器
35 /// </summary>
36 /// <param name="xPage"></param>
37 public static void Bind(XPage xPage)
38 {
39 xPage.delegateSyncLoadUI = Resources.Load;
40 //xPage.delegateAsyncLoadUI = ResourcesMgr.Load;
41 }
42 }
43
44 public class XPage
45 {
46 public string m_pageName;
47 public string m_loadPath;
48 public GameObject m_pageInst;
49 public Transform m_pageTrans;
50 public EPageType m_pageType = EPageType.None;
51 public EPageMode m_pageMode = EPageMode.DoNothing;
52 public EPageState m_currState = EPageState.NONE;
53
54 private string m_luaPageCtrl;
55 private string m_luaPageView;
56
57 //delegate load ui function.
58 public Func<string, Object> delegateSyncLoadUI = null;
59 public Action<string, Action<Object>> delegateAsyncLoadUI = null;
60
61 public XPage(string pageName, string loadPath)
62 {
63 m_pageName = pageName;
64 m_loadPath = loadPath;
65 }
66
67 public void Awake()
68 {
69 m_luaPageCtrl = m_pageName + "Ctrl";
70 m_luaPageView = m_pageName + "View";
71 //Debug.LogError("call lua awake :(" + m_pageName + "Ctrl)");
72 Util.CallMethod(m_luaPageCtrl, "Awake",this);
73
74 //设置type和mode
75 //m_pageType = EPageType.PopUp;
76 //m_pageMode = EPageMode.HideOtherAndNeedBack;
77 }
78
79 public void Start()
80 {
81 m_currState = EPageState.OPEN;
82 m_pageInst.gameObject.SetActive(true);
83 AnchorUIGameObject();
84 //Debug.LogError("call lua start :(" + m_pageName + "Ctrl)");
85 Util.CallMethod(m_luaPageView, "Start", this.m_pageInst);
86 Util.CallMethod(m_luaPageCtrl, "Start");
87 }
88
89 public void Rest()
90 {
91 m_currState = EPageState.OPEN;
92 m_pageInst.gameObject.SetActive(true);
93 //Debug.LogError("call lua rest :(" + m_pageName + "Ctrl)");
94 Util.CallMethod(m_luaPageCtrl, "Rest");
95 }
96
97 public void Hide()
98 {
99 m_currState = EPageState.HIDE;
100 m_pageInst.gameObject.SetActive(false);
101 //Debug.LogError("call lua hide :(" + m_pageName + "Ctrl)");
102 Util.CallMethod(m_luaPageCtrl, "Hide");
103 }
104
105 public void Destroy()
106 {
107 m_currState = EPageState.CLOSE;
108 GameObject.Destroy(m_pageInst);
109 //Debug.LogError("call lua destroy :(" + m_pageName + "Ctrl)");
110 Util.CallMethod(m_luaPageCtrl, "Destroy");
111 }
112
113 public void LoadSync(Action<GameObject> callback)
114 {
115 if (this.m_pageInst == null && string.IsNullOrEmpty(m_loadPath) == false)
116 {
117 GameObject go = null;
118 if (delegateSyncLoadUI != null)
119 {
120 Object o = delegateSyncLoadUI(m_loadPath);
121 go = o != null ? GameObject.Instantiate(o) as GameObject : null;
122 }
123 else
124 {
125 go = GameObject.Instantiate(Resources.Load(m_loadPath)) as GameObject;
126 }
127
128 if (go == null)
129 {
130 Debug.LogError("[UI] Cant sync load your ui prefab.");
131 return;
132 }
133
134 m_pageInst = go;
135 m_pageTrans = go.transform;
136
137 if (callback != null)
138 callback(go);
139 }
140 else
141 {
142 if (callback != null)
143 callback(m_pageInst);
144 }
145 }
146
147 public void LoadAsync(Action<GameObject> callback)
148 {
149 XPageRoot.Instance.StartCoroutine(AsyncShow(callback));
150 }
151
152 IEnumerator AsyncShow(Action<GameObject> callback)
153 {
154 if (this.m_pageInst == null && string.IsNullOrEmpty(m_loadPath) == false)
155 {
156 GameObject go = null;
157 bool _loading = true;
158 delegateAsyncLoadUI(m_loadPath, (o) =>
159 {
160 go = o != null ? GameObject.Instantiate(o) as GameObject : null;
161
162 _loading = false;
163
164 m_pageInst = go;
165 m_pageTrans = go.transform;
166
167 if (callback != null)
168 callback(go);
169 });
170
171 float _t0 = Time.realtimeSinceStartup;
172 while (_loading)
173 {
174 if (Time.realtimeSinceStartup - _t0 >= 10.0f)
175 {
176 Debug.LogError("[UI] WTF async load your ui prefab timeout!");
177 yield break;
178 }
179 yield return null;
180 }
181 }
182 else
183 {
184 if (callback != null)
185 callback(m_pageInst);
186 }
187 }
188
189 protected void AnchorUIGameObject()
190 {
191 if (XPageRoot.Instance == null || m_pageInst == null)
192 return;
193
194 GameObject ui = m_pageInst;
195
196 //check if this is ugui or (ngui)?
197 Vector3 anchorPos = Vector3.zero;
198 Vector2 sizeDel = Vector2.zero;
199 Vector3 scale = Vector3.one;
200 if (ui.GetComponent<RectTransform>() != null)
201 {
202 anchorPos = ui.GetComponent<RectTransform>().anchoredPosition;
203 sizeDel = ui.GetComponent<RectTransform>().sizeDelta;
204 scale = ui.GetComponent<RectTransform>().localScale;
205 }
206 else
207 {
208 anchorPos = ui.transform.localPosition;
209 scale = ui.transform.localScale;
210 }
211
212 EPageType type = this.m_pageType;
213 if (type == EPageType.Normal)
214 {
215 ui.transform.SetParent(XPageRoot.Instance.normalRoot);
216 }
217 else if(type == EPageType.PopUp)
218 {
219 ui.transform.SetParent(XPageRoot.Instance.popupRoot);
220 }
221 else if (type == EPageType.Fixed)
222 {
223 ui.transform.SetParent(XPageRoot.Instance.fixedRoot);
224 }
225 else if (type == EPageType.Toppest)
226 {
227 ui.transform.SetParent(XPageRoot.Instance.ToppestRoot);
228 }
229
230 if (ui.GetComponent<RectTransform>() != null)
231 {
232 ui.GetComponent<RectTransform>().anchoredPosition = anchorPos;
233 ui.GetComponent<RectTransform>().sizeDelta = sizeDel;
234 ui.GetComponent<RectTransform>().localScale = scale;
235 }
236 else
237 {
238 ui.transform.localPosition = anchorPos;
239 ui.transform.localScale = scale;
240 }
241 }
242 }
XpageMgr:
1 using UnityEngine;
2 using System.Collections.Generic;
3 using System;
4
5 public class XPageMgr
6 {
7 private static XPageMgr m_inst;
8 public static XPageMgr Inst
9 {
10 get
11 {
12 if (m_inst == null)
13 m_inst = new XPageMgr();
14 return m_inst;
15 }
16 }
17
18 public XPage currShowXPage;//当前正打开的界面
19 public Stack<XPage> m_pageNeedBackPool = new Stack<XPage>();//需要返回的页面的池子,栈,先进后出
20 public Dictionary<string, XPage> m_pageDic = new Dictionary<string, XPage>();//所有的页面
21
22
23 public int GetNeedBackCount()
24 {
25 return m_pageNeedBackPool.Count;
26 }
27
28 /// <summary>
29 /// 获取所有面板
30 /// </summary>
31 /// <returns></returns>
32 private List<XPage> GetAllPages()
33 {
34 return new List<XPage>(m_pageDic.Values);
35 }
36
37 /// <summary>
38 /// 检查面板打开类型
39 /// </summary>
40 /// <param name="currXPage"></param>
41 private void CheckPageMode(XPage currXPage)
42 {
43 if (currXPage.m_pageMode == EPageMode.DoNothing)
44 {
45
46 }
47 else if (currXPage.m_pageMode == EPageMode.HideOtherOnly)
48 {
49 HideOtherPages(currXPage);
50 }
51 else if (currXPage.m_pageMode == EPageMode.HideOtherAndNeedBack)
52 {
53 HideOtherPages(currXPage);
54 m_pageNeedBackPool.Push(currXPage);
55 }
56 }
57
58 private void HideOtherPages(XPage currXPage)
59 {
60 List<XPage> xpages = GetAllPages();
61 int count = xpages.Count;
62 for (int i = 0; i < count; i++)
63 {
64 XPage curr = xpages[i];
65 if (curr.Equals(currXPage))
66 continue;
67 if (curr.m_currState == EPageState.OPEN && curr.m_pageType != EPageType.Fixed && curr.m_pageType != EPageType.Normal )
68 {
69 curr.Hide();
70 }
71 }
72 }
73
74 /// <summary>
75 /// 检测面板是否在队列里
76 /// </summary>
77 /// <param name="pageName"></param>
78 /// <returns></returns>
79 private bool CheckPageExist(string pageName)
80 {
81 if (m_pageDic.ContainsKey(pageName))
82 {
83 return true;
84 }
85 else
86 {
87 return false;
88 }
89 }
90
91 /// <summary>
92 /// 用相对路径获取面板名称
93 /// </summary>
94 /// <param name="pageLoadPath"></param>
95 /// <returns></returns>
96 private string GetPageName(string pageLoadPath)
97 {
98 string pageName = pageLoadPath.Substring(pageLoadPath.LastIndexOf("/") + 1);
99 return pageName;
100 }
101
102 #region api
103 /// <summary>
104 /// 打开面板
105 /// </summary>
106 /// <param name="isSync">是否同步加载</param>
107 /// <param name="pageLoadPath">加载的相对路径</param>
108 public void ShowPage(bool isSync, string pageLoadPath)
109 {
110 string pageName = GetPageName(pageLoadPath);
111 bool isExist = CheckPageExist(pageName);
112 XPage currXPage = null;
113 if (isExist)
114 {
115 currXPage = m_pageDic[pageName];
116 if(currXPage.m_currState == EPageState.HIDE)
117 {
118 CheckPageMode(currXPage);
119 currXPage.Rest();
120 currShowXPage = currXPage;
121 }
122 }
123 else
124 {
125 //add
126 currXPage = new XPage(pageName, pageLoadPath);
127 currXPage.Awake();
128 XPageLoadBind.Bind(currXPage);
129 if (isSync)
130 {
131 currXPage.LoadSync((go) =>
132 {
133 m_pageDic.Add(pageName, currXPage);
134 currShowXPage = currXPage;
135 CheckPageMode(currXPage);
136 currXPage.Start();
137
138 });
139 }
140 else
141 {
142 currXPage.LoadAsync((go) =>
143 {
144 m_pageDic.Add(pageName, currXPage);
145 currShowXPage = currXPage;
146 CheckPageMode(currXPage);
147 currXPage.Start();
148 });
149 }
150 }
151 }
152
153 /// <summary>
154 /// 隐藏当前的页面
155 /// </summary>
156 public bool HideCurrPage()
157 {
158 if (currShowXPage != null)
159 {
160 if (currShowXPage.m_pageMode == EPageMode.HideOtherAndNeedBack)
161 {
162 if (m_pageNeedBackPool.Count > 0)
163 {
164 if (m_pageNeedBackPool.Peek().Equals(currShowXPage))
165 {
166 XPage topPage = m_pageNeedBackPool.Pop();
167 topPage.Hide();
168 currShowXPage = null;
169
170 if (m_pageNeedBackPool.Count > 0)
171 {
172 XPage _curr = m_pageNeedBackPool.Peek();
173 _curr.Rest();
174 currShowXPage = _curr;
175 }
176 }
177 }
178 }
179 else
180 {
181 if (currShowXPage.m_currState == EPageState.OPEN)
182 {
183 currShowXPage.Hide();
184 currShowXPage = null;
185 }
186 }
187
188 return true;
189 }
190 else
191 {
192 Debug.Log("currShowPage is null");
193 return false;
194 }
195 }
196
197 /// <summary>
198 ///隐藏指定面板
199 /// </summary>
200 /// <param name="pageName">Page name.</param>
201 public void HidePage(string pageName)
202 {
203 bool isExist = CheckPageExist(pageName);
204 if (isExist)
205 {
206 XPage _currXpage = m_pageDic[pageName];
207 if(_currXpage.m_currState == EPageState.OPEN)
208 _currXpage.Hide();
209 }
210
211 }
212
213 /// <summary>
214 /// 销毁所有面板
215 /// </summary>
216 public void CloseAllPages()
217 {
218 List<XPage> allPages = GetAllPages();
219 int count = allPages.Count;
220 for (int i = 0; i < count; i++)
221 {
222 allPages[i].Destroy();
223 allPages[i] = null;
224 }
225 m_pageDic.Clear();
226 m_pageNeedBackPool.Clear();
227 }
228 #endregion
229
230 /// <summary>
231 /// 销毁
232 /// </summary>
233 public void Destroy()
234 {
235 CloseAllPages();
236 currShowXPage = null;
237 m_pageDic = null;
238 m_pageNeedBackPool = null;
239 m_inst = null;
240 Debug.Log("~XPageMgr was destroy");
241 }
242 }
XPageRoot:
1 using UnityEngine;
2 using System.Collections;
3 using UnityEngine.UI;
4 using UnityEngine.EventSystems;
5
6 /// <summary>
7 /// Init The UI Root
8 /// </summary>
9 public class XPageRoot : MonoBehaviour
10 {
11 private static XPageRoot m_Instance = null;
12 public static XPageRoot Instance
13 {
14 get
15 {
16 if (m_Instance == null)
17 {
18 InitRoot();
19 }
20 return m_Instance;
21 }
22 }
23
24 public Transform root;
25 public Transform normalRoot;//Canvas order in layer 0
26 public Transform popupRoot;//250
27 public Transform fixedRoot;//500
28 public Transform ToppestRoot;//750
29 public Camera uiCamera;
30
31 static void InitRoot()
32 {
33 GameObject go = new GameObject("UIRoot");
34 go.layer = LayerMask.NameToLayer("UI");
35 m_Instance = go.AddComponent<XPageRoot>();
36 go.AddComponent<RectTransform>();
37 m_Instance.root = go.transform;
38
39 Canvas can = go.AddComponent<Canvas>();
40 can.renderMode = RenderMode.ScreenSpaceCamera;
41 can.pixelPerfect = true;
42 GameObject camObj = new GameObject("UICamera");
43 camObj.layer = LayerMask.NameToLayer("UI");
44 camObj.transform.parent = go.transform;
45 camObj.transform.localPosition = new Vector3(0, 0, -100f);
46 Camera cam = camObj.AddComponent<Camera>();
47 cam.clearFlags = CameraClearFlags.Depth;
48 cam.orthographic = true;
49 cam.farClipPlane = 200f;
50 can.worldCamera = cam;
51 m_Instance.uiCamera = cam;
52 cam.cullingMask = 1 << 5;
53 cam.nearClipPlane = -50f;
54 cam.farClipPlane = 50f;
55
56 //add audio listener
57 camObj.AddComponent<AudioListener>();
58 camObj.AddComponent<GUILayer>();
59
60 CanvasScaler cs = go.AddComponent<CanvasScaler>();
61 cs.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
62 cs.referenceResolution = new Vector2(1136f, 640f);
63 cs.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
64
65 ////add auto scale camera fix size.
66 //TTCameraScaler tcs = go.AddComponent<TTCameraScaler>();
67 //tcs.scaler = cs;
68
69 //set the raycaster
70 //GraphicRaycaster gr = go.AddComponent<GraphicRaycaster>();
71
72 GameObject subRoot = CreateSubCanvasForRoot(go.transform, 0);
73 subRoot.name = "NormalRoot";
74 m_Instance.normalRoot = subRoot.transform;
75
76 subRoot = CreateSubCanvasForRoot(go.transform, 250);
77 subRoot.name = "PopupRoot";
78 m_Instance.popupRoot = subRoot.transform;
79
80 subRoot = CreateSubCanvasForRoot(go.transform, 500);
81 subRoot.name = "FixedRoot";
82 m_Instance.fixedRoot = subRoot.transform;
83
84 subRoot = CreateSubCanvasForRoot(go.transform, 750);
85 subRoot.name = "ToppestRoot";
86 m_Instance.ToppestRoot = subRoot.transform;
87
88 //add Event System
89 GameObject esObj = GameObject.Find("EventSystem");
90 if (esObj != null)
91 {
92 GameObject.DestroyImmediate(esObj);
93 }
94
95 GameObject eventObj = new GameObject("EventSystem");
96 eventObj.layer = LayerMask.NameToLayer("UI");
97 eventObj.transform.SetParent(go.transform);
98 eventObj.AddComponent<EventSystem>();
99 if (!Application.isMobilePlatform || Application.isEditor)
100 {
101 eventObj.AddComponent<UnityEngine.EventSystems.StandaloneInputModule>();
102 }
103 else
104 {
105 eventObj.AddComponent<UnityEngine.EventSystems.TouchInputModule>();
106 }
107
108
109 }
110
111 static GameObject CreateSubCanvasForRoot(Transform root, int sort)
112 {
113 GameObject go = new GameObject("canvas");
114 go.transform.parent = root;
115 go.layer = LayerMask.NameToLayer("UI");
116
117 Canvas can = go.AddComponent<Canvas>();
118 RectTransform rect = go.GetComponent<RectTransform>();
119 rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, 0);
120 rect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, 0);
121 rect.anchorMin = Vector2.zero;
122 rect.anchorMax = Vector2.one;
123
124 can.overrideSorting = true;
125 can.sortingOrder = sort;
126
127 go.AddComponent<GraphicRaycaster>();
128
129 return go;
130 }
131
132 void OnDestroy()
133 {
134 m_Instance = null;
135 }
136 }
ToLua使用:
熟悉Tolua的同学都知道要
_GT(typeof(XPage)),
_GT(typeof(XPageMgr)),
_GT(typeof(EPageType)),
_GT(typeof(EPageMode)),
_GT(typeof(EventTriggerListener)),
如果你还不知道ToLua是什么,那么你先去了解一下咯。
这样,这些类,在lua里就能用了。
初始化:
1 require "Logic/LuaClass"
2 require "Common/define"
3 require "Common/functions"
4
5 --管理器--
6 XGame = {};
7 local this = XGame;
8
9 local game;
10 local transform;
11 local gameObject;
12 local WWW = UnityEngine.WWW;
13
14 function XGame.InitViewPanels()
15 for i = 1, #XPanelNames do
16 require ("XUI/XView/"..tostring(XPanelNames[i]).."View")
17 require ("XUI/XCtrl/"..tostring(XPanelNames[i]).."Ctrl")
18 end
19 end
20
21 xpageMgr = XPageMgr.Inst
22
23 --初始化完成,发送链接服务器信息--
24 function XGame.OnInitOK()
25 --注册LuaView--
26 this.InitViewPanels();
27
28
29 logWarn('LuaFramework InitOK--->>>');
30 end
当你调XPageMgr.Inst.ShowPage(true, "UI/UIPrefab/MainPanel");来显示MainPanel的面板时
我的做法是去调lua里面MainPanelCtrl,MainPanelView。
MainPanelCtrl
1 local transform;
2 local gameObject;
3
4 MainPanelCtrl = {};
5 local this = MainPanelCtrl;
6
7 --构建函数--
8 function MainPanelCtrl.New()
9 logWarn("MainPanelCtrl.New--->>");
10 return this;
11 end
12
13 function MainPanelCtrl.Awake(xpage)
14 --logWarn('MainPanelCtrl Awake--->>>'..'xpage name:'..xpage.m_pageName);
15 xpage.m_pageType = EPageType.Normal;
16 xpage.m_pageMode = EPageMode.DoNothing;
17 end
18
19 function MainPanelCtrl.Start()
20 logWarn('MainPanelCtrl Start--->>>');
21 local eventTriggerListener = EventTriggerListener.Get(MainPanelView.packageBtn.gameObject);
22 eventTriggerListener:AddClick(MainPanelView.packageBtn,this.OnClick);
23 end
24
25 function MainPanelCtrl.Rest()
26 logWarn('MainPanelCtrl Rest--->>>');
27 end
28
29 function MainPanelCtrl.Hide()
30 logWarn('MainPanelCtrl Hide--->>>');
31 end
32
33 function MainPanelCtrl.Destroy()
34 logWarn('MainPanelCtrl Destroy--->>>');
35 end
36
37 --单击事件--
38 function MainPanelCtrl.OnClick(go)
39 xpageMgr:ShowPage(true,"UI/UIPrefab/TopBar");
40 xpageMgr:ShowPage(true,"UI/Prompt/PromptPanel");
41 end
MainPanelView
1 local transform;
2 local gameObject;
3
4 MainPanelView = {};
5 local this = MainPanelView;
6
7
8 function MainPanelView.Start(obj)
9 gameObject = obj;
10 transform = obj.transform;
11 logWarn('MainPanelView Start--->>>'..gameObject.name);
12
13 this.packageBtn = transform:FindChild("Button").gameObject;
14 end
其他面板也是这个道理,所以我的结构是这样的。

结束语:
1.代码写的很粗糙,但是基本满足我目前的需求。
2.再次感谢开源,避免重复造轮子,毕竟人生苦短,当你有想法时,也许可以进行二次开发。
原文地址:http://www.cnblogs.com/joeshifu/p/5655064.html


浙公网安备 33010602011771号