import { _decorator, Component, director,Node, Vec3, Widget} from 'cc'; import { Singleton } from './Singleton'; import { Constants } from '../../data/Constants'; import { Utils } from '../../utils/Utils'; import { ResUtil } from '../../utils/ResUtil'; const { ccclass, property } = _decorator; interface PageActive{ show: () => {}, hide: () => {}, back: () => {}, } @ccclass("uiManager") export class uiManager extends Singleton { //tabbar pages主页面节点放在这个容器中 private pageUIs: string = 'pageUIs'; //pop dialog出来的节点放在这个容器中 private popUIs: string = 'popUIs'; //页面缓存 public panels = new Map (); /** * 展示场景 * @param sceneName 场景名字 * @param delay 延迟的时间 */ public showScene(sceneName: string, delay: number = 0.1): void { if (delay) { setTimeout(() => { director.loadScene(sceneName); }, delay * 1000); } else { director.loadScene(sceneName); } } /** * 展示一个resources资源包里的节点 * @param path Prefab的路径名称 * @param args 给组建传递的参数 * @param cb 展示完成的回调函数 * @returns */ public async show(path: string, args?: any, cb?: Function): Promise{ const pageName: string = path.split('/').pop(); if (!args) {args = [];} const scriptName = pageName.replace(/^\w/, (c) => c.toUpperCase()); let panel: any = this.panels.get(path); if(!panel){ panel = await ResUtil.loadRes(path); this.panels.set(path, panel); } if (!panel || !(panel instanceof Node)) return; //动态添加页面的路径path信息,在关闭和销毁的时候用到 panel['_uiPath'] = path; let isMain = Object.values(Constants.mainUIs).includes(path); const name: string = isMain ? this.pageUIs : this.popUIs; let parent:Node = this.getCurentSceneRoot(); parent = Utils.findName(parent,name) ?? parent; panel.parent = parent; panel.active = true; panel.getComponent(Widget)?.updateAlignment(); if(isMain){ parent.children.forEach((e:Node) => { e.setPosition(new Vec3(e.name == pageName ? 0 : 500000,0,1)); }); }else{ panel.setSiblingIndex(parent.children.length); } const comp = panel.getComponent(scriptName); if (comp && (comp as Component & PageActive)['show']){ (comp as Component & PageActive)['show'].apply(comp, args); } if(typeof cb === 'function') {cb?.(panel)}; } /** * 根据堆栈页面顺序返回到某一个页面 * @param path 返回某一个界面 * @param args 返回的附带参数 * @param cb 回调 * @returns */ public pop(path?: string,args?: any,cb?: Function){ let canvas:Node = this.getCurentSceneRoot(); let popUIs:Node = Utils.findName(canvas,this.popUIs); let isMain:boolean = Object.values(Constants.mainUIs).includes(path); let comp:any = null; if(Utils.isNull(path)){ if(popUIs.children.length > 0){//关闭存在的popUIs最后一个节点 let node: Node = popUIs.children.slice(-2)[0]; node.parent = null; const scriptName = node.name.replace(/^\w/, (c) => c.toUpperCase()); comp = node.getComponent(scriptName); }else{//返回主页面的上一层节点 comp = this.getPageComponent(Constants.mainUIs.main); comp.tabBarIndex = comp.preIndexs.slice(-2)[0]; } }else{ const pageName: string = path.split('/').pop(); const scriptName = pageName.replace(/^\w/, (c) => c.toUpperCase()); if (!args) {args = [];} if(isMain){ comp = this.getPageComponent(Constants.mainUIs.main); comp.tabBarIndex = comp.sceneNames.indexOf(path); popUIs.removeAllChildren(); }else{ let panel: Node = this.panels.get(path); let targetIndex = popUIs.children.findIndex(n => n.name == pageName); if (targetIndex !== -1) { popUIs.children.slice(targetIndex + 1).forEach(n => { n.parent = null; }); popUIs.children.splice(targetIndex + 1); } panel.setSiblingIndex(panel.parent.children.length); comp = panel.getComponent(scriptName); } } if(comp && (comp as Component & PageActive)['pop']){ (comp as Component & PageActive)['pop'].apply(comp, args); } if(typeof cb === 'function') {cb?.()}; } /** * 直接关闭固定的名字中的一个页面 * @param path Prefab的路径名称 * @param cb 展示完成的回调函数 * @returns */ public hide(path: string,cb?: Function){ if(!this.panels.has(path))return; let panel: Node = this.panels.get(path); const pageName: string = path.split('/').pop(); const scriptName = pageName.replace(/^\w/, (c) => c.toUpperCase()); let isMain = Object.values(Constants.mainUIs).includes(path); if(isMain){ let container = Utils.findName(this.getCurentSceneRoot(),this.pageUIs); container.children.forEach((e:Node) => { e.setPosition(new Vec3((e.name == pageName ? 500000 : 0),0,1)); }); }else{ panel.parent = null; const comp = panel.getComponent(scriptName); if(comp && (comp as Component & PageActive)['hide']){ (comp as Component & PageActive)['hide'].apply(comp); } } if(typeof cb === 'function') {cb?.()}; } /** * 从缓存页面中获取一个脚本 * @param path 缓存的路径 * @param scriptName 不传默认获取path名字最后一个字符串作为脚本的名字 * @returns */ public getPageComponent(path: string,scriptName?:string): any{ if(!this.panels.has(path)){ return null; }else{ const sName = path.split('/').pop().replace(/^\w/, (c) => c.toUpperCase()); let node: Node = this.panels.get(path); return node.getComponent(scriptName ?? sName); } } /** *从缓存页面中获取一个页面 * @param path 缓存的路径 */ public getPageNode(path: string): Node{ if(Utils.isNull(path))return null; if(!this.panels.has(path))return null; return this.panels.get(path); } /** * 在界面中显示的节点是否存在 */ public hasPageNode(path: string): boolean{ if(Utils.isNull(path))return false; let name = path.split('/').pop(); let canvas:Node = this.getCurentSceneRoot(); let pages = Utils.findName(canvas,this.pageUIs); let popUIs = Utils.findName(canvas,this.popUIs); let nodes = pages.children.concat(popUIs.children) return nodes.some(e=>e.name == name); } /** * 得到当前场景的节点的根节点 * @returns 根结点 */ public getCurentSceneRoot(): Node { return director.getScene().getChildByName('Canvas'); } } //全局单例 export const uiMgr = uiManager.ins();