import { IUIItem } from './UIDef'; const { ccclass, property } = cc._decorator; enum UILoadingState { none, loading, show, close, }; class UILoadingHandle { private static _idBase = 0; private _instId: number = 0; constructor(){ this._instId = UILoadingHandle._idBase++; } public get instId(): number { return this._instId; } state: UILoadingState = UILoadingState.loading; asset: cc.Asset; node: cc.Node; uiData: IUIItem; destory(){ if(cc.isValid(this.node, true)) { this.node.destroy(); } this.asset && this.asset.decRef(); this.state = UILoadingState.close; } } /** * @en the `User Interface Manager`, handles some stuffs like the ui loads,ui layers,resizing etc. * @zh UI管理器,处理UI加载,层级,窗口变化等 * * */ export class UIMgr { private static _inst: UIMgr; public static get inst(): UIMgr { if (this._inst == null) { this._inst = new UIMgr(); } return this._inst; } private _uiCanvas: cc.Node; private _uiRoot: cc.Node; handleArr:UILoadingHandle[] = []; // 允许打开两个相同的界面 private createFullScreenNode() { let canvas = this._uiCanvas; let node = new cc.Node(); node.group = this._uiCanvas.group; node.width = canvas.width; node.height = canvas.height; let widget = node.addComponent(cc.Widget); widget.isAlignBottom = true; widget.isAlignTop = true; widget.isAlignLeft = true; widget.isAlignRight = true; widget.left = 0; widget.right = 0; widget.top = 0; widget.bottom = 0; return node; } /** * @en setup this UIMgr,`don't call more than once`. * @zh 初始化UIMgr,`不要多次调用` * */ public setup(uiCanvas: cc.Node | cc.Prefab, maxLayers: number, layerNames?: Array) { if (this._uiCanvas) { return; } if (!uiCanvas) { cc.error('uiCanvas must be a cc.Node or cc.Prefab'); return; } if (uiCanvas instanceof cc.Node) { this._uiCanvas = uiCanvas; } else { this._uiCanvas = cc.instantiate(uiCanvas); cc.director.getScene().addChild(this._uiCanvas); } this._uiCanvas.name = '$tgxUICanvas$'; // cc.game.addPersistRootNode(this._uiCanvas); layerNames ||= []; this._uiRoot = this.createFullScreenNode(); this._uiRoot.name = 'ui_root' this._uiCanvas.addChild(this._uiRoot); //create layers for (let i = 0; i < maxLayers; ++i) { let layerNode = this.createFullScreenNode(); layerNode.name = 'ui_layer_' + (layerNames[i] ? layerNames[i] : i); this._uiRoot.addChild(layerNode); layerNode.on(cc.Node.EventType.CHILD_REMOVED, this.uiRemove, this); } } private uiRemove(node: cc.Node){ let index = this.handleArr.findIndex((v)=>{ return v.node.uuid == node.uuid; }); if(index != -1) { this.hideUIIndex(index); } } public getLayerNode(layerIndex: number): cc.Node { return this._uiRoot.children[layerIndex] || this._uiRoot; } public getUI(uiData: IUIItem): UILoadingHandle { return this.handleArr.find((v)=>{return v.uiData.prefab == uiData.prefab}); } public isShowing(uiData: IUIItem): boolean { let find = this.getUI(uiData); if(!find) return false; return find.state == UILoadingState.loading || find.state == UILoadingState.show; } public showUI(uiData: IUIItem) { let handle = new UILoadingHandle(); handle.state = UILoadingState.loading; handle.uiData = uiData; this.handleArr.push(handle); cc.resources.load(uiData.prefab, cc.Prefab, (err, res)=>{ if(err){ console.log(err); this.showUI(uiData); return; } if(handle.state == UILoadingState.loading){ let node = cc.instantiate(res); let layer = this.getLayerNode(uiData.layer); layer.addChild(node); handle.state = UILoadingState.show; handle.asset = res; handle.node = node; res.addRef(); } else{ cc.assetManager.releaseAsset(res); } }) return handle; } //注:同一个prefab可能会有多个实例,只有一个实例时调用。 public hideUI(uiData: IUIItem){ let index = this.handleArr.findIndex((v)=>{return v.uiData.prefab == uiData.prefab});; if(index==-1) return; this.hideUIIndex(index); } public hideUIIndex(index: number){ let find = this.handleArr[index]; find.destory(); this.handleArr.splice(index, 1); } } window['uiMgr'] = function(){ return UIMgr.inst; }