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.再次感谢开源,避免重复造轮子,毕竟人生苦短,当你有想法时,也许可以进行二次开发。

 

posted @ 2016-07-09 00:58  Joe师傅  阅读(7897)  评论(2编辑  收藏  举报