UIManager.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import { _decorator, Component, director,Node, Vec3, Widget} from 'cc';
  2. import { Singleton } from './Singleton';
  3. import { Constants } from '../../data/Constants';
  4. import { Utils } from '../../utils/Utils';
  5. import { ResUtil } from '../../utils/ResUtil';
  6. const { ccclass, property } = _decorator;
  7. interface PageActive{
  8. show: () => {},
  9. hide: () => {},
  10. back: () => {},
  11. }
  12. @ccclass("uiManager")
  13. export class uiManager extends Singleton {
  14. //tabbar pages主页面节点放在这个容器中
  15. private pageUIs: string = 'pageUIs';
  16. //pop dialog出来的节点放在这个容器中
  17. private popUIs: string = 'popUIs';
  18. //页面缓存
  19. public panels = new Map <string, Node>();
  20. /**
  21. * 展示场景
  22. * @param sceneName 场景名字
  23. * @param delay 延迟的时间
  24. */
  25. public showScene(sceneName: string, delay: number = 0.1): void {
  26. if (delay) {
  27. setTimeout(() => {
  28. director.loadScene(sceneName);
  29. }, delay * 1000);
  30. } else {
  31. director.loadScene(sceneName);
  32. }
  33. }
  34. /**
  35. * 展示一个resources资源包里的节点
  36. * @param path Prefab的路径名称
  37. * @param args 给组建传递的参数
  38. * @param cb 展示完成的回调函数
  39. * @returns
  40. */
  41. public async show(path: string, args?: any, cb?: Function): Promise<Node>{
  42. const pageName: string = path.split('/').pop();
  43. if (!args) {args = [];}
  44. const scriptName = pageName.replace(/^\w/, (c) => c.toUpperCase());
  45. let panel: any = this.panels.get(path);
  46. if(!panel){
  47. panel = await ResUtil.loadRes(path);
  48. this.panels.set(path, panel);
  49. }
  50. if (!panel || !(panel instanceof Node)) return;
  51. //动态添加页面的路径path信息,在关闭和销毁的时候用到
  52. panel['_uiPath'] = path;
  53. let isMain = Object.values(Constants.mainUIs).includes(path);
  54. const name: string = isMain ? this.pageUIs : this.popUIs;
  55. let parent:Node = this.getCurentSceneRoot();
  56. parent = Utils.findName(parent,name) ?? parent;
  57. panel.parent = parent;
  58. panel.active = true;
  59. panel.getComponent(Widget)?.updateAlignment();
  60. if(isMain){
  61. parent.children.forEach((e:Node) => {
  62. e.setPosition(new Vec3(e.name == pageName ? 0 : 500000,0,1));
  63. });
  64. }else{
  65. panel.setSiblingIndex(parent.children.length);
  66. }
  67. const comp = panel.getComponent(scriptName);
  68. if (comp && (comp as Component & PageActive)['show']){
  69. (comp as Component & PageActive)['show'].apply(comp, args);
  70. }
  71. if(typeof cb === 'function') {cb?.(panel)};
  72. }
  73. /**
  74. * 根据堆栈页面顺序返回到某一个页面
  75. * @param path 返回某一个界面
  76. * @param args 返回的附带参数
  77. * @param cb 回调
  78. * @returns
  79. */
  80. public pop(path?: string,args?: any,cb?: Function){
  81. let canvas:Node = this.getCurentSceneRoot();
  82. let popUIs:Node = Utils.findName(canvas,this.popUIs);
  83. let isMain:boolean = Object.values(Constants.mainUIs).includes(path);
  84. let comp:any = null;
  85. if(Utils.isNull(path)){
  86. if(popUIs.children.length > 0){//关闭存在的popUIs最后一个节点
  87. let node: Node = popUIs.children.slice(-2)[0];
  88. node.parent = null;
  89. const scriptName = node.name.replace(/^\w/, (c) => c.toUpperCase());
  90. comp = node.getComponent(scriptName);
  91. }else{//返回主页面的上一层节点
  92. comp = this.getPageComponent(Constants.mainUIs.main);
  93. comp.tabBarIndex = comp.preIndexs.slice(-2)[0];
  94. }
  95. }else{
  96. const pageName: string = path.split('/').pop();
  97. const scriptName = pageName.replace(/^\w/, (c) => c.toUpperCase());
  98. if (!args) {args = [];}
  99. if(isMain){
  100. comp = this.getPageComponent(Constants.mainUIs.main);
  101. comp.tabBarIndex = comp.sceneNames.indexOf(path);
  102. popUIs.removeAllChildren();
  103. }else{
  104. let panel: Node = this.panels.get(path);
  105. let targetIndex = popUIs.children.findIndex(n => n.name == pageName);
  106. if (targetIndex !== -1) {
  107. popUIs.children.slice(targetIndex + 1).forEach(n => {
  108. n.parent = null;
  109. });
  110. popUIs.children.splice(targetIndex + 1);
  111. }
  112. panel.setSiblingIndex(panel.parent.children.length);
  113. comp = panel.getComponent(scriptName);
  114. }
  115. }
  116. if(comp && (comp as Component & PageActive)['pop']){
  117. (comp as Component & PageActive)['pop'].apply(comp, args);
  118. }
  119. if(typeof cb === 'function') {cb?.()};
  120. }
  121. /**
  122. * 直接关闭固定的名字中的一个页面
  123. * @param path Prefab的路径名称
  124. * @param cb 展示完成的回调函数
  125. * @returns
  126. */
  127. public hide(path: string,cb?: Function){
  128. if(!this.panels.has(path))return;
  129. let panel: Node = this.panels.get(path);
  130. const pageName: string = path.split('/').pop();
  131. const scriptName = pageName.replace(/^\w/, (c) => c.toUpperCase());
  132. let isMain = Object.values(Constants.mainUIs).includes(path);
  133. if(isMain){
  134. let container = Utils.findName(this.getCurentSceneRoot(),this.pageUIs);
  135. container.children.forEach((e:Node) => {
  136. e.setPosition(new Vec3((e.name == pageName ? 500000 : 0),0,1));
  137. });
  138. }else{
  139. panel.parent = null;
  140. const comp = panel.getComponent(scriptName);
  141. if(comp && (comp as Component & PageActive)['hide']){
  142. (comp as Component & PageActive)['hide'].apply(comp);
  143. }
  144. }
  145. if(typeof cb === 'function') {cb?.()};
  146. }
  147. /**
  148. * 从缓存页面中获取一个脚本
  149. * @param path 缓存的路径
  150. * @param scriptName 不传默认获取path名字最后一个字符串作为脚本的名字
  151. * @returns
  152. */
  153. public getPageComponent(path: string,scriptName?:string): any{
  154. if(!this.panels.has(path)){
  155. return null;
  156. }else{
  157. const sName = path.split('/').pop().replace(/^\w/, (c) => c.toUpperCase());
  158. let node: Node = this.panels.get(path);
  159. return node.getComponent(scriptName ?? sName);
  160. }
  161. }
  162. /**
  163. *从缓存页面中获取一个页面
  164. * @param path 缓存的路径
  165. */
  166. public getPageNode(path: string): Node{
  167. if(Utils.isNull(path))return null;
  168. if(!this.panels.has(path))return null;
  169. return this.panels.get(path);
  170. }
  171. /**
  172. * 在界面中显示的节点是否存在
  173. */
  174. public hasPageNode(path: string): boolean{
  175. if(Utils.isNull(path))return false;
  176. let name = path.split('/').pop();
  177. let canvas:Node = this.getCurentSceneRoot();
  178. let pages = Utils.findName(canvas,this.pageUIs);
  179. let popUIs = Utils.findName(canvas,this.popUIs);
  180. let nodes = pages.children.concat(popUIs.children)
  181. return nodes.some(e=>e.name == name);
  182. }
  183. /**
  184. * 得到当前场景的节点的根节点
  185. * @returns 根结点
  186. */
  187. public getCurentSceneRoot(): Node {
  188. return director.getScene().getChildByName('Canvas');
  189. }
  190. }
  191. //全局单例
  192. export const uiMgr = uiManager.ins();