框架概述html
1.界面的加載、卸載緩存
2.打開、關閉、隱藏、顯示界面,這邊隱藏是指界面被遮擋的意思,通常來講,界面被遮住時,應該關閉界面的更新服務器
3.界面棧的管理,主要是用於場景切換時須要回到上一個場景打開的界面棧網絡
4.須要的功能:圖片鏡像(節省資源)、滑動列表(複用)、模糊背景等框架
注意點:ide
1.界面的生成:class的生成、預製體的實例化,類和實例的關聯。oop
業務打開一個界面須要傳入界面的標識(枚舉、或者字符串),如何經過這個標識找到預製體並實例化go、如何生成指定的界面view,如何綁定view和go佈局
如何銷燬一個界面,清除ab緩存、清除引用關係、destory go動畫
2.界面的層級關係:每次打開一個新的UI,都將它堆入棧,關閉時出棧。這個棧是一個特殊的棧,例如它能夠實現,某個不在棧頂的UI,能夠「TOP」到棧頂。ui
打開一個界面:1.從已打開界面搜索,避免重複打開界面。2.從緩存界面搜索,避免重複加載。3.隱藏棧頂界面。4.打開新界面
關閉一個界面:1.關閉界面並加入緩存。2.從已打開界面棧頂取出一個界面,顯示該界面。3.重複步驟2直到打開一個全屏界面。
退出場景:1.全部界面入棧,當再次回到場景時能夠恢復界面棧。2.關閉界面
進入場景:1.若是須要恢復界面棧,從界面棧取出界面並打開顯示該界面。2.重複1步驟直到打開一個全屏界面。3.不須要恢復:打開當前場景的界面。
3.界面間的通訊:最好不要有界面之間的通訊,界面的更新經過數據(邏輯)類發送消息通知給界面。例如使用道具後界面的更新,數據類接收到服務器道具使用成功後,發送道具更新消息BAG_DATA_UPDATE,須要更新的界面監聽BAG_DATA_UPDATE消息並刷新界面。
4.界面打開動畫控制。統一使用Animator(Animation),且每一個界面最多隻有一個Animator(Animation),界面獲取焦點時調用Animator的Play方法播放動畫。
5.界面特效控制:遊戲會有不少進入界面播放一次的特效,若是你的界面關閉不是使用SetActive處理的(例如設置layer、移到屏幕外等),那麼在你的界面再次打開時特效不會再次被播放。
6.界面內使用的對象怎麼獲取?(例如要修改界面的某個text)
每一個須要在腳本內加載的對象都掛載一個UIExportItem對象,在界面初始化時統一收集這些對象,並存儲在一個map裏給界面使用
7.界面的模糊效果怎麼作?能夠參考:https://blog.csdn.net/zhaoguanghui2012/article/details/51462284,原理就是使用一個shader均值周圍的像素。
8.彈窗適配,例如實現如下效果:彈窗顯示與item的某條邊對齊
如上所示,w爲target的包圍盒寬度,例如綠色框的長度,h爲包圍盒的高度,例如綠色框的高度。包圍盒大小能夠使用unity的RectTransformUtility.CalculateRelativeRectTransformBounds接口獲取。
那麼target的座標怎麼結算呢?
target.x = anchor.x + anchor.w/2 + offect.x + target.w/2
target.y - target.h/2 - offect.y = anchor.y - anchor.h/2 即 target.y = anchor.y - anchor.h/2 + target.h/2 + offect.y
固然對齊方式不同,計算方法也不同,例如左上、左下等,並且還須要考慮界面佈局是否會超框,超框如何處理等。
具體能夠參考:http://www.javashuo.com/article/p-palqpfue-et.html
UI模塊分如下幾部分:
1.界面類:負責界面的邏輯,提供生命週期方法供業務使用,如OnOpen、OnClose等。負責界面的生成、銷燬(以及界面ab包的加載、卸載)。子窗口、子item的管理(生成、緩存、銷燬)
2.管理類:提供界面的生命週期管理,如打開、關閉、顯示(得到焦點,顯示在最上層)、隱藏(失去焦點,能夠理解成被其餘界面擋住了)一個界面、打開、關閉一堆界面(場景切入、切出時)。緩存界面。維護窗體中間的層級關係。
3.配置類:負責配置界面的預製體路徑、類、界面類型等參數。
4.功能類:滑動列表、圖片鏡像、模糊、彈窗適配、通用的標題、通用的tab等。
5.item類,例如界面的滑動列表的子項。
導出的層級
詳細代碼以下:
1、ViewDefine:定義類的配置:這邊主要是一些界面定義以及界面的配置,經過配置類名能夠用反射實例化界面類,經過配置的路徑能夠加載並實例化預製體。
using System.Collections.Generic; using UnityEngine; public class ViewDefine { public enum ViewType { MAIN = 1, // 主窗口(全屏) POPUP = 2, // 彈窗 FIXED = 3, // 固化窗口 SCENE = 4, // 場景UI窗口 GUIDE = 5, // 引導UI窗口 } public enum ViewPopModal { Blur = 1, // 帶有模糊效果的模態彈窗 Lucency_ImPenetrable = 2, // 無模糊,不可穿透 Lucency_Penetrate = 3, // 無模糊, 可穿透 } public enum ViewLoadStateDefine { NONE = 0, LOADING = 1, LOADED = 2, } public enum ViewOnLoadDefine { Cache = 1, Destroy = 2, } public enum ViewAlignmentType { UpperLeft = 0, UpperCenter = 1, UpperRight = 2, MiddleLeft = 3, MiddleCenter = 4, MiddleRight = 5, LowerLeft = 6, LowerCenter = 7, LowerRight = 8, } public enum ViewID { TOAST, // 吐司界面 TOAST_BATTLE, // 戰鬥中吐司界面 NETWAIT, // 網絡等待界面 NETWORK_TIPS, // 網絡異常提示 } private static Dictionary<int, string> _viewConfig = new Dictionary<int, string> { { (int)ViewID.TOAST, "ToastView,Prefab/Common/ToastPanel" }, { (int)ViewID.TOAST_BATTLE, "ToastBattleView,Prefab/Common/ToastBattlePanel" }, { (int)ViewID.NETWAIT, "NetwaitView,Prefab/Common/NetwaitPanel" } }; public static string GetViewType(ViewID viewID) { string config = _viewConfig[(int)viewID]; if (string.IsNullOrEmpty(config)) { Debug.LogErrorFormat("未配置界面路徑 : {0}", viewID); return null; } string[] split = config.Split(','); return split[0]; } public static string GetViewPath(ViewID viewID) { string config = _viewConfig[(int)viewID]; if (string.IsNullOrEmpty(config)) { Debug.LogErrorFormat("未配置界面路徑 : {0}", viewID); return null; } string[] split = config.Split(','); return split[1]; } }
2、UIBase ,ui元素基類,主要提供go的銷燬以及導入界面須要引用的對象並保存在_viewObj裏,業務能夠經過_viewObj["對象名"]訪問對象而不用去定義參數。
using System.Collections.Generic; using UnityEngine; /// <summary> /// item、view的基類,提供預製體的生成、卸載(ab包的維護),提供子節點的生成 /// </summary> public class UIBase { protected GameObject gameObject; protected Transform transform; public string Name { get; set; } protected Dictionary<string, Object> _viewObj = new Dictionary<string, Object>();//導出的界面對象 public virtual void Ctor(GameObject obj, Transform parent) { if (obj != null) { gameObject = obj; transform = obj.transform; ExportHierarchy(); if (parent != null) { transform.SetParent(parent); transform.localPosition = Vector3.zero; transform.localScale = Vector3.zero; } } } protected virtual void OnLoad() { } public void SetActive(bool isShow) { gameObject.SetActive(isShow); } public virtual void Dispose() { if (gameObject != null) { GameObject.Destroy(gameObject); transform = null; gameObject = null; } } protected void ExportHierarchy() { if (gameObject) { UIHierarchy hierarchy = gameObject.GetComponent<UIHierarchy>(); if (hierarchy) { foreach (var item in hierarchy.widgets) { _viewObj.Add(item.name, item.item); } foreach (var item in hierarchy.externals) { _viewObj.Add(item.name, item.item); } } } } }
3、UIItemBase ,item類,主要是提供OnItemOpen、OnItemClose方法,方便item在界面打開和關閉時監聽(移除)事件
/// <summary> /// 界面item /// </summary> public class UIItemBase:UIBase { protected ViewBase parentView; protected bool isItemOpen = false; public virtual void OnItemOpen() { isItemOpen = true; } public virtual void OnItemClose() { isItemOpen = false; } public bool IsItemOpen() { return isItemOpen; } public void SetParentView(ViewBase parent) { parentView = parent; } }
4、PanelBase ,子界面、界面的基類。主要是提供子item的生成、維護。
using System.Collections.Generic; using UnityEngine; /// <summary> /// 全部界面的基類,包括子窗口、全部的界面 /// 這個類主要功能是:提供給子界面生個生成、維護item的接口 /// </summary> public class PanelBase:UIBase { protected bool isOpen = false; protected Dictionary<string, Queue<UIItemBase>> childItemPool = new Dictionary<string, Queue<UIItemBase>>(); //緩存item的池子 protected List<UIBase> subItems = new List<UIBase>();//維護子對象,包括子窗口、子item /// <summary> /// UIModule調用,用於打開一個界面。若是該界面還未加載,會調用Load加載界面 /// </summary> /// <param name="args"></param> 界面參數 public virtual void Open(params object[] args) { } public virtual void Close() { } public bool IsOpen() { return isOpen; } /// <summary> /// 生成一個子item /// </summary> /// <param name="className"></param> 子item的類名 /// <param name="prefabs"></param> 子item的預製體 /// <param name="parent"></param> 子item的父節點 /// <returns></returns> protected UIItemBase GenerateItem(string className, GameObject prefabs, Transform parent) { Queue<UIItemBase> pool = childItemPool[className]; if (pool != null && pool.Count > 0) { return pool.Dequeue(); } UIItemBase item = InstantiateItem(className, prefabs, parent); AddSubItem(item); return item; } protected void GenerateItemList(string className, GameObject prefabs, Transform parent, int count, ref List<UIItemBase> container) { while (container.Count < count) { UIItemBase item = GenerateItem(className, prefabs, transform); container.Add(item); } while (container.Count > count) { UIItemBase item = container[container.Count]; container.Remove(item); RecyleItem(item); } } protected UIItemBase InstantiateItem(string className, GameObject prefabs, Transform parent) { GameObject obj = GameObject.Instantiate(prefabs, parent); UIItemBase item = (UIItemBase)UIModule.Instance.CreateUIClass(className); item.Ctor(obj, parent); item.Name = className; return item; } /// <summary> /// 回收子item /// </summary> /// <param name="item"></param> protected void RecyleItem(UIItemBase item) { RemoveSubItem(item); Queue<UIItemBase> cachePool = childItemPool[item.Name]; if (cachePool == null) { cachePool = new Queue<UIItemBase>(); } cachePool.Enqueue(item); item.SetActive(false); if (item.IsItemOpen()) { item.OnItemClose(); } } protected void RecyleItemList(int count, ref List<UIItemBase> container) { while (container.Count > count) { UIItemBase item = container[container.Count]; RecyleItem(item); container.Remove(item); } } protected void ClearCache() { foreach (var pool in childItemPool.Values) { foreach (var item in pool) { item.Dispose(); } pool.Clear(); } childItemPool.Clear(); } /// <summary> /// 添加子對象,包括item、childview /// </summary> /// <param name="item"></param> protected void AddSubItem(UIBase item) { if (subItems.Contains(item)) { Debug.Log("item已存在"); return; } subItems.Add(item); } protected void RemoveSubItem(UIBase item) { if (subItems.Contains(item)) { subItems.Remove(item); } } protected void RemoveAllSubItem() { foreach (var item in subItems) { item.Dispose(); } subItems.Clear(); } protected void OnOpenSubItem() { foreach (var item in subItems) { if (item is UIItemBase) { (item as UIItemBase).OnItemOpen(); } } } protected void OnCloseSubItem() { foreach (var item in subItems) { if (item is UIItemBase) { (item as UIItemBase).OnItemClose(); } } } public override void Dispose() { base.Dispose(); RemoveAllSubItem(); ClearCache(); } }
5、ChildViewBase :重寫了Open、Close方法
public class ChildViewBase:PanelBase { /// <summary> /// UIModule調用,用於打開一個界面。若是該界面還未加載,會調用Load加載界面 /// </summary> /// <param name="args"></param> 界面參數 public override void Open(params object[] args) { if (!isOpen) { SetActive(true); OnOpenSubItem(); isOpen = true; } } public override void Close() { if (isOpen) { OnCloseSubItem(); SetActive(false); isOpen = false; } } }
6、ViewBase :全部界面基類,主要是提供了界面的加載、卸載(注意ab的加、卸載),子界面的添加、維護。
using System.Collections.Generic; using UnityEngine; /// <summary> /// 界面基類,能夠生成ChildView /// </summary> public class ViewBase: PanelBase { protected object[] openParam; protected ViewDefine.ViewType viewType; protected ViewDefine.ViewLoadStateDefine loadState = ViewDefine.ViewLoadStateDefine.NONE; protected bool isHide = false; protected float closeTime = 0;//用於回收計時 public ViewDefine.ViewID ViewID { get; set; } /// <summary> /// 打開界面,一次OnOpen對應一次OnClose,子類實現 /// </summary> /// <param name="args"></param> protected virtual void OnOpen(params object[] args){ } /// <summary> /// 用於刷新界面,每次調用OpenView都會調用,避免業務重複打開界面 /// </summary> /// <param name="args"></param> protected virtual void OnRefreshView(params object[] args) { } /// <summary> /// 得到焦點。1.打開界面。2.上一層界面被關閉,從新得到焦點 /// </summary> protected virtual void OnEnabled() { } public virtual void Update(float dt) { } /// <summary> /// 失去焦點。1.關閉界面。2.有新的界面打開。 /// </summary> protected virtual void OnDisable() { } protected virtual void OnClose() { } /// <summary> /// UIModule調用,用於打開一個界面。若是該界面還未加載,會調用Load加載界面 /// </summary> /// <param name="args"></param> 界面參數 public override void Open(params object[] args) { openParam = args; if (loadState == ViewDefine.ViewLoadStateDefine.LOADED) { DoRealOpen(); } else { Load(); } } /// <summary> /// 加載界面,包括界面的ab包,ab的依賴包,最終返回一個Prefab用於實例化界面 /// </summary> private void Load() { if (loadState != ViewDefine.ViewLoadStateDefine.NONE) return; loadState = ViewDefine.ViewLoadStateDefine.LOADING; ResManager.Instance.LoadPrefab(ViewDefine.GetViewPath(ViewID), "", LoadFinish); } private void LoadFinish(object prefab) { loadState = ViewDefine.ViewLoadStateDefine.LOADED; gameObject = GameObject.Instantiate((GameObject)prefab, UIModule.Instance.GetViewRoot(viewType)); transform = gameObject.transform; ExportHierarchy(); OnLoad(); DoRealOpen(); } private void DoRealOpen() { if (!isOpen) { SetActiveEx(true); OnOpen(openParam); OnOpenSubItem(); } OnRefreshView(openParam); ShowView(); } /// <summary> /// 顯示、隱藏界面,這邊使用的方式是將界面移到屏幕外。 /// 另外幾種作法是:1.SetActive直接隱藏go。2.設置Scale爲0。3.設置layer out /// </summary> /// <param name="isActive"></param> 是否顯示 public void SetActiveEx(bool isActive) { if (transform) { if (isActive) { transform.localPosition = Vector3.zero; } else { transform.localPosition = new Vector3(10000, 10000, 0); } } } public virtual void ShowView() { SetActiveEx(true); transform.SetAsFirstSibling(); if (!isHide) { isHide = true; OnEnabled(); } } /// <summary> /// 界面失去焦點,若是是打開彈窗,不隱藏該界面。 /// </summary> /// <param name="keepShow"></param> public virtual void HideView(bool keepShow = false) { SetActiveEx(keepShow); if (isHide) { isHide = false; OnDisable(); } } public override void Close() { if (isOpen) { UIModule.Instance.CloseView(ViewID); } } public virtual void CloseView() { HideView(); if (isOpen) { OnClose(); OnCloseSubItem(); CloseSubPanel(); closeTime = Time.realtimeSinceStartup; } } public float GetCloseTime() { return closeTime; } public bool IsPopView() { return viewType == ViewDefine.ViewType.POPUP; } public bool IsMainView() { return viewType == ViewDefine.ViewType.MAIN; } public bool IsFixedView() { return viewType == ViewDefine.ViewType.FIXED; } public bool IsShow() { return !isHide; } public bool IsOnLoadDestroy() { return loadState == ViewDefine.ViewLoadStateDefine.LOADING; } protected List<ChildViewBase> childView = new List<ChildViewBase>(); protected ChildViewBase AddChildPanel(string className, GameObject obj, Transform parent) { ChildViewBase view = (ChildViewBase)UIModule.Instance.CreateUIClass(className); view.Ctor(obj, parent); childView.Add(view); AddSubItem(view); return view; } protected void CloseSubPanel() { foreach (var item in childView) { if (item.IsOpen()) { item.Close(); } } } }
7、UIHierarchy:保存了業務導出的引用對象。ExportPanelHierarchy尋找UIExportItem 元素並保存到UIHierarchy
public class UIHierarchy : MonoBehaviour { [System.Serializable] public class ItemInfo { public string name; public Object item; public ItemInfo() { } public ItemInfo(string _name, Object _item) { name = _name; item = _item; } } // 控件 public List<ItemInfo> widgets; public void SetWidgets(List<ItemInfo> data) { if (data.Count == 0) return; if (widgets == null) { widgets = new List<ItemInfo>(); } widgets.Clear(); widgets.AddRange(data); } // 外部引用 public List<ItemInfo> externals; } using UnityEngine; [DisallowMultipleComponent] public class UIExportItem : MonoBehaviour { public string FieldName; }
using UnityEngine; using UnityEngine.UI; using UnityEditor; using System.Collections.Generic; public class ExportPanelHierarchy { /// <summary> /// 導出組件優先級 /// </summary> private static System.Type[] ms_componentTypes = { typeof(Button), typeof(InputField), typeof(ScrollRect), typeof(Dropdown), typeof(Image), typeof(RawImage), typeof(Scrollbar), typeof(Slider), typeof(Text), typeof(Toggle), typeof(GridLayoutGroup), typeof(HorizontalOrVerticalLayoutGroup), typeof(LayoutElement), typeof(CanvasGroup), typeof(ToggleGroup), typeof(TextMesh), typeof(Animation), typeof(Camera), typeof(SpriteRenderer), }; static Object FindComponent(GameObject go) { Object component = null; for (int i = 0; i < ms_componentTypes.Length; ++i) { component = go.GetComponent(ms_componentTypes[i]); if (component != null) { break; } } return component; } //生成嵌套UI層級 public static void ExportNested(Object obj) { GameObject root = obj as GameObject; if (root == null) return; UIHierarchy hierarchy = root.GetComponent<UIHierarchy> (); if(hierarchy==null) { hierarchy = root.AddComponent<UIHierarchy>(); } //生成根節點層級 List<UIHierarchy.ItemInfo> fields = new List<UIHierarchy.ItemInfo>(); GetChildComponentUtilHierarchy (root.transform, fields); hierarchy.SetWidgets(fields); //生成子panel層級 UIHierarchy[] childHierarchys = root.GetComponentsInChildren<UIHierarchy>(true); for(int i=1; i<childHierarchys.Length; i++) { UIHierarchy childHrcy = childHierarchys [i]; List<UIHierarchy.ItemInfo> childUIItem = new List<UIHierarchy.ItemInfo>(); GetChildComponentUtilHierarchy (childHrcy.transform, childUIItem); childHrcy.SetWidgets(childUIItem); } EditorUtility.SetDirty(root); AssetDatabase.SaveAssets(); } //導出傳入節點的層級,直到某個子節點掛有UIHierarchy組件 private static void GetChildComponentUtilHierarchy(Transform transRoot, List<UIHierarchy.ItemInfo> fields) { for(int i=0; i<transRoot.childCount; i++) { Transform trans = transRoot.GetChild (i); UIHierarchy hrchy = trans.GetComponent<UIHierarchy> (); if(hrchy!=null) { fields.Add (new UIHierarchy.ItemInfo(hrchy.name, hrchy)); continue; } UIExportItem uiItem = trans.GetComponent<UIExportItem>(); if (uiItem != null) { Object fieldItem = FindComponent(uiItem.gameObject); if (fieldItem == null) { fieldItem = uiItem.transform; } fields.Add(new UIHierarchy.ItemInfo(uiItem.name, fieldItem)); } GetChildComponentUtilHierarchy (trans, fields); } } }
8、UIModule:核心管理類,提供給全局惟一的打開界面方法,維護層級棧。維護界面緩存。
using System.Collections.Generic; using System.Reflection; using UnityEngine; public class UIModule { #region Instance private static UIModule m_Instance; public static UIModule Instance { get { return m_Instance ?? (m_Instance = new UIModule()); } } #endregion private const float CACHE_TIME = 30;//界面緩存時間 private int curSceneID = 0;//當前打開的場景id,每一個場景都有本身的層級棧 private int curViewID = 0;//當前打開的界面id private int lastViewID = 0;//上一個界面id private List<int> openViewList;//當前打開的界面列表,按順序 private Dictionary<int, ViewBase> cacheView;//緩存區,等待銷燬,從緩存區取要移除 private Dictionary<int, List<int>> naviStack;//場景的層級棧,key爲場景id,用於維護場景 private Dictionary<int, ViewBase> viewPool;//保存全部ViewBase的引用,包括緩存區的,界面銷燬時須要移除。 private Dictionary<ViewDefine.ViewType, Transform> viewRoot;//界面實例化出來的父節點,不一樣界面的父節點不同。 private Transform uiRoot;//ui根節點 private float lastCheckCacheTime;//上次檢查緩存時間,一秒檢查一次 public void Init() { openViewList = new List<int>(); cacheView = new Dictionary<int, ViewBase>(); naviStack = new Dictionary<int, List<int>>(); viewPool = new Dictionary<int, ViewBase>(); uiRoot = GameObject.Find("UIRoot").transform; viewRoot = new Dictionary<ViewDefine.ViewType, Transform> { { ViewDefine.ViewType.MAIN, uiRoot.Find("main") }, { ViewDefine.ViewType.POPUP, uiRoot.Find("main") }, { ViewDefine.ViewType.FIXED, uiRoot.Find("fixed") }, { ViewDefine.ViewType.GUIDE, uiRoot.Find("guide") } }; lastCheckCacheTime = Time.realtimeSinceStartup; } public Transform GetViewRoot(ViewDefine.ViewType viewType) { if (viewType == ViewDefine.ViewType.SCENE) { return null; } else { return viewRoot[viewType]; } } public void Update(float dt) { int openCount = openViewList.Count; ViewBase view; for (int i = 0; i < openCount; i++) { int viewId = openViewList[i]; if (viewPool.TryGetValue(viewId, out view)) { view.Update(dt); } } //清楚緩存時間到了的界面 float curTime = Time.realtimeSinceStartup; if (curTime - lastCheckCacheTime > 1) { foreach (var item in cacheView) { if (curTime - item.Value.GetCloseTime() > CACHE_TIME) { item.Value.Dispose(); cacheView.Remove(item.Key); viewPool.Remove(item.Key); } } } lastCheckCacheTime = curTime; } /// <summary> /// 外部調用 打開一個窗口的惟一方式 /// 若是上一個界面lastView存在,須要把lastView入棧 /// </summary> /// <param name="viewID"></param> /// <param name="param"></param> 界面打開參數,給業務使用的 /// <returns></returns> public ViewBase OpenView(ViewDefine.ViewID viewID, params object[] param) { int viewKey = (int)viewID; ViewBase view = FindOpenView(viewKey); if (view == null) { view = CreateView(viewID); if (view == null) { Debug.LogErrorFormat("OpenView CreateView Fail..viewID:", viewID); return null; } view.ViewID = viewID; AddOpenView(viewKey); } if (curViewID == viewKey) { view.Open(param); return view; } if (view.IsPopView() || view.IsMainView()) { lastViewID = curViewID; curViewID = viewKey; if (lastViewID > 0) { OnBackstage(lastViewID); } } view.Open(param); return view; } private ViewBase FindOpenView(int viewKey) { ViewBase view = null; if (openViewList.Contains(viewKey)) { viewPool.TryGetValue(viewKey, out view); } return view; } private void AddOpenView(int viewKey) { if (openViewList.Contains(viewKey)) { Debug.LogFormat("界面已打開:{0}", viewKey); return; } openViewList.Add(viewKey); } private void RemoveOpenView(int viewKey) { if (openViewList.Contains(viewKey)) { openViewList.Remove(viewKey); } } /// <summary> /// 建立新的view,先從緩存裏面找 /// </summary> /// <param name="viewID"></param> /// <returns></returns> private ViewBase CreateView(ViewDefine.ViewID viewID) { int viewKey = (int)viewID; ViewBase view = GetViewFromCache(viewKey); if (view == null) { string viewName = ViewDefine.GetViewType(viewID); //加載程序集,建立程序集裏面的 命名空間.類型名 實例 object ect = CreateUIClass(viewName); view = (ViewBase)ect;//類型轉換並返回 viewPool.Add((int)viewID, view); } return view; } public object CreateUIClass(string calssName) { return Assembly.GetExecutingAssembly().CreateInstance(calssName); } private ViewBase GetViewFromCache(int viewKey) { ViewBase view = null; if (cacheView.TryGetValue(viewKey, out view)) { cacheView.Remove(viewKey); } return view; } private void AddViewToCache(int viewKey, ViewBase view) { cacheView[viewKey] = view; } private int GetTopViewOfStack() { List<int> stack = naviStack[curSceneID]; if (stack == null || stack.Count == 0) { return 0; } return stack[stack.Count]; } private ViewBase PopViewFormStack() { List<int> stack = naviStack[curSceneID]; if (stack == null || stack.Count == 0) { return null; } int index = stack.Count; int viewId = stack[index]; ViewBase view = GetViewByKey(viewId); stack.RemoveAt(index); if (view.IsPopView()) { for (int i = index-1; i > 0; i--) { ViewBase temp = GetViewByKey(stack[i]); temp.SetActiveEx(true); if (temp.IsMainView()) break; } } curViewID = viewId; view.ShowView(); AddOpenView(viewId); return view; } /// <summary> /// 向棧裏添加元素 /// </summary> /// <param name="viewKey"></param> /// <param name="isForce"></param>true時,棧裏存在會先移除在加入,不然棧裏存在就不處理了 private void AddViewToStack(int viewKey, bool isForce = true) { List<int> stack = naviStack[curSceneID]; if (stack == null) { stack = new List<int>(); } if (stack.Contains(viewKey)) { if (isForce) { stack.Remove(viewKey); } else { return; } } stack.Add(viewKey); } private void RemoveFromStack(int viewKey) { List<int> stack = naviStack[curSceneID]; if (stack == null || stack.Count == 0) { return; } if (stack.Contains(viewKey)) { stack.Remove(viewKey); } } /// <summary> /// 進入後臺 /// </summary> /// <param name="viewKey"></param> private void OnBackstage(int viewKey) { AddViewToStack(viewKey); ViewBase lastView = GetViewByKey(lastViewID); if (lastView.IsPopView()) { lastView.HideView(true); } else { lastView.HideView(false); } } /// <summary> /// 關閉界面,若是是當前打開界面,須要從棧頂彈出新的界面 /// </summary> /// <param name="viewKey"></param> private void InsertClose(int viewKey) { RemoveView(viewKey); if (viewKey == curViewID) { curViewID = 0; PopViewFormStack(); } else { RemoveFromStack(viewKey); } } /// <summary> /// 移除界面,從打開列表移除,添加到緩存 /// </summary> /// <param name="viewKey"></param> private void RemoveView(int viewKey) { RemoveOpenView(viewKey); RemoveFromStack(viewKey); ViewBase view = GetViewByKey(viewKey); view.CloseView(); AddViewToCache(viewKey, view); } private ViewBase GetViewByKey(int viewKey) { return viewPool[viewKey]; } public void CloseView(ViewDefine.ViewID viewID) { int viewKey = (int)viewID; if (openViewList.Contains(viewKey)) { InsertClose(viewKey); } } public void CloseCurView() { if (curViewID > 0) { CloseView((ViewDefine.ViewID)curViewID); } } /// <summary> /// 進入新的場景 /// </summary> /// <param name="sceneID"></param> 場景id /// <param name="isNative"></param> 是否須要打開ui棧,isBack=true時,從當前場景的棧頂彈出界面 public void EnterScene(int sceneID, bool isBack) { curSceneID = sceneID; if (naviStack[sceneID] == null) { naviStack[sceneID] = new List<int>(); } if (isBack) { PopViewFormStack(); } } /// <summary> /// 退出當前場景 /// </summary> /// <param name="pushToStack"></param> 是否壓棧,用於場景返回時恢復ui層級 public void ExitScene(bool pushToStack) { int count = openViewList.Count; ViewBase temp = null; int viewKey = 0; for (int i = count; i > 0; i--) { viewKey = openViewList[i]; temp = GetViewByKey(viewKey); if (temp != null && (temp.IsMainView() || temp.IsPopView())) { if (pushToStack) { RemoveOpenView(viewKey); AddViewToStack(viewKey, false); } else { RemoveView(viewKey); } } } List<int> stack = naviStack[curSceneID]; if (stack != null) { for (int i = 0; i < stack.Count; i++) { ViewBase view = GetViewByKey(stack[i]); view.HideView(); } } curViewID = 0; lastViewID = 0; } }