using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using UnityEngine; using UnityEngine.UI; using Debug = UnityEngine.Debug; namespace XUI { public class UIStack : UIPool { [Tooltip("是否为每个组创建一个物体")] public bool CreateGroupGameObject = true; public bool CreateCanvasPerObject = true; private int CanvasSortOffset = 20; private Canvas ThisCanvas; [System.NonSerialized] public Stack Pages = new Stack(); protected override void Awake() { base.Awake(); this.ThisCanvas = GetComponent(); } /// /// 叠加一个组 /// /// public UIGroup Overlay(IEnumerable prefabs, params object[] args) { if (this.Pages.Count == 0) { this.Pages.Push(new UIPage()); } var page = this.Pages.Peek(); var lastGroup = page.Last; if (lastGroup != null) { lastGroup.Value.SendBeenOverlay(); } var group = new UIGroup(this, prefabs); page.AddLast(group); UpdateCanvasOrder(); group.SendEnterStack(args); return group; } /// /// 覆盖一个组 /// /// /// public UIGroup Cover(IEnumerable prefabs, bool destroyBefore, params object[] args) { //关闭底下的界面 if (this.Pages.Count > 0) { var lastPage = this.Pages.Peek(); lastPage.SendBeenCover(); foreach (var @group in lastPage) { foreach (var uiPageItem in @group) { uiPageItem.Instance.SetActive(false); // Despawn(uiPageItem.Instance, destroyBefore);//这里不使用回收,为了避免复用之后,退回该界面状态丢失 } } } //生成新层 UIPage newPage = new UIPage(); this.Pages.Push(newPage); var newGroup = new UIGroup(this, prefabs); newPage.AddLast(newGroup); UpdateCanvasOrder(); newGroup.SendEnterStack(args); return newGroup; } /// /// 退回到上一界面 /// public virtual void Back(bool destroy = true) { if (this.Pages.Count == 0) { UnityEngine.Debug.LogError("没有任何界面可以回退"); return; } //回收最前面的界面 var lastPage = this.Pages.Peek(); var lastGroup = lastPage.Last.Value; lastPage.RemoveLast(); lastGroup.SendLeaveStack(); lastGroup.Despawn(destroy); //显示上一个界面,如果当前页面还有组,则只需通知,如果当前页面没有组了,则需要把下一页全部显示出来 if (lastPage.Count == 0) { this.Pages.Pop(); if (this.Pages.Count == 0) { return; } lastPage = this.Pages.Peek(); foreach (var g in lastPage) { foreach (var i in g) { i.Instance.SetActive(true); } // g.Spawn(); } lastPage.SendDeCover(); //注意:这里要先spawn在发消息 } else { lastPage.Last.Value.SendDeOverlay(); } UpdateCanvasOrder(); } /// /// 移除指定的group /// /// /// public void BackSpecified(UIGroup @group, bool destroy = true) { if (this.Pages.Count == 0) { UnityEngine.Debug.LogError("fail"); return; } var lastPage = this.Pages.Peek(); var lastGroup = lastPage.Last.Value; var tmpPage = new Stack(); var tmpStack = new Stack(); while (lastGroup != group) { //查找,直到指定界面 tmpStack.Push(lastGroup); lastPage.RemoveLast(); if (lastPage.Count == 0) { var tmpPopPage = this.Pages.Pop(); tmpPage.Push(tmpPopPage); //将推出的页面重新入栈 while (tmpStack.Count > 0) { tmpPopPage.AddLast(tmpStack.Pop()); } if (this.Pages.Count == 0) { return; } lastPage = this.Pages.Peek(); } lastGroup = lastPage.Last.Value; } //回收指定的界面 lastPage = this.Pages.Peek(); lastGroup = lastPage.Last.Value; lastPage.RemoveLast(); lastGroup.SendLeaveStack(); lastGroup.Despawn(destroy); //将退出的页面重新入栈 while (tmpStack.Count > 0) { lastPage.AddLast(tmpStack.Pop()); } while (tmpPage.Count > 0) { this.Pages.Push(tmpPage.Pop()); } UpdateCanvasOrder(); } /// /// 退回到指定界面Group /// public void BackTo(UIGroup group, bool destroy = true) { if (this.Pages.Count == 0) { UnityEngine.Debug.LogError("fail"); return; } var lastPage = this.Pages.Peek(); var lastGroup = lastPage.Last.Value; bool decover = false; bool deoverlay = false; while (lastGroup != group) { //一直回收,直到指定界面 lastPage.RemoveLast(); lastGroup.SendLeaveStack(); lastGroup.Despawn(destroy); deoverlay = true; if (lastPage.Count == 0) { this.Pages.Pop(); if (this.Pages.Count == 0) { return; } lastPage = this.Pages.Peek(); decover = true; deoverlay = false; } lastGroup = lastPage.Last.Value; } //达到指定页面 if (decover) { //如果经历过翻页,需要生成它 // lastGroup.Spawn(); foreach (var i in lastGroup) { i.Instance.SetActive(true); } lastPage.SendDeCover(); //注意:这里要先spawn在发消息 } if (deoverlay) { //如果被叠加过,需要发送反叠加消息 lastGroup.SendDeOverlay(); } UpdateCanvasOrder(); } public void UpdateCanvasOrder() { if (!this.CreateCanvasPerObject) { return; } var page = this.Pages.Peek(); if (page == null) { return; } int i = 0; foreach (var group in page) { foreach (var item in @group) { if (item.Instance.activeSelf) { item.InstanceCanvas.overrideSorting = true; item.InstanceCanvas.sortingLayerID = this.ThisCanvas.sortingLayerID; item.InstanceCanvas.sortingOrder = i * this.CanvasSortOffset + this.ThisCanvas.sortingOrder; i++; } } } } internal UIItem PrefabToUIItem(GameObject prefab, GameObject parent) { var ins = Spawn(prefab); if (parent != null) { ins.transform.SetParent(parent.transform); } Canvas canvas = null; if (this.CreateCanvasPerObject) { canvas = ins.GetOrAddComponent(); ins.GetOrAddComponent(); } return new UIItem(prefab, ins, canvas); } public virtual void OnUIGroupCreated(UIGroup uiGroup) { } } }