import { StringMap } from "../../Collections/StringMap"; import Config from "../../Config"; import { gameMethod } from "../../common/gameMethod"; import GameDataCenter from "../../data/GameDataCenter"; import { GUIEvent } from "../../data/const/EventConst"; import { PlatFormDevType } from "../../data/const/TypeConst"; import { ViewZOrder } from "../../data/const/ViewZOrder"; import EventMng from "../../manager/EventMng"; import { Singleton } from "../../manager/Singleton"; import AssetsBundleMgr from "../../utils/AssetsBundleMgr"; import { PromiseDefault } from "../Promise/SpecialPromise"; import { ResCollector } from "../compment/ResCollector"; import { ResKeeper } from "../compment/ResKeeper"; import FguiLoadMgr from "./FguiLoadMgr"; import { IDisposable } from "./Interface/IDisposable"; import { ILateUpdate } from "./Interface/ILateUpdate"; import { IUpdate } from "./Interface/IUpdate"; import { FguiClass, FguiView, ViewType } from "./mvc/FguiView"; export default class FguiMgr extends Singleton() implements IUpdate, ILateUpdate, IDisposable { /** 记录图层节点的Map */ private _layerNodeMap: Map = new Map(); /** 已开启过的ui */ private _opened: StringMap = new StringMap(); /** 缓存被关闭的ui */ private _closed: StringMap = new StringMap(); /** 记录所加载的包 */ private _addPkged: StringMap = new StringMap(); Init(): void { fgui.GRoot.create(); //设置默认字体 AssetsBundleMgr.loadBundle("commonView", (error, bundle) => { if (error) { console.error("load font bundle fail:", error) return } bundle.load("font/Alimama_ShuHeiTi_Bold", cc.Font, (error, assset) => { if (error) { console.error("load font fail:", error) return } fgui.registerFont('Alimama_ShuHeiTi_Bold', assset); fgui.UIConfig.defaultFont = 'Alimama_ShuHeiTi_Bold' }) }) fgui.GRoot.inst.width = Config.safeAreaRect.width fgui.GRoot.inst.height = Config.realHeight fgui.GRoot.inst.node.y = Config.realHeight + Config.safeAreaRect.y / 2 this._layerNodeMap = new Map(); // 创建所有UI层级 Object.values(ViewZOrder).forEach((layer) => { if (typeof layer === 'number') { const layerName = ViewZOrder[layer]; this.createLayer(layerName + 'Layer', layer); } }); } private createLayer(name: string, zOrder: number): fgui.GComponent { const layer = new fgui.GComponent(); layer.name = name; layer.node.name = name; layer.sortingOrder = zOrder; fgui.GRoot.inst.addChild(layer); layer.makeFullScreen(); this._layerNodeMap.set(zOrder, layer); return layer; } /** * @param callback 打开完毕回调函数 * @param intent 传入到UI的参数 */ public openUI(uiClass: FguiClass, zOrder: number = ViewZOrder.UI, callback?: Function, intent?: any): Promise { if (CC_PREVIEW) console.log(`打开页面${uiClass.getViewName()}`); const viewKey = uiClass.getViewName(); if (this._opened.ContainsKey(viewKey)) { console.log(`FguiMgr::Open ${viewKey} has already opened.`); return; } if (this.getCacheView(uiClass, zOrder, callback)) { return; } let pkgName = uiClass.getPkgName(); EventMng.emit(GUIEvent.SHOW_MASK, pkgName, true); if (fgui.UIPackage.getByName(pkgName) == null) { // 加载uipackage FguiLoadMgr.loadPackage(pkgName, pkgName, async (error, pkg) => { if (error) { EventMng.emit(GUIEvent.SHOW_MASK, pkgName, false) console.error(`FguiMgr LoadPackage[${pkgName}] error: ${error}`); return; } this.CreateView(uiClass, zOrder, intent, callback); }); } else { this.CreateView(uiClass, zOrder, intent, callback); } } /** 从缓存中加载页面 */ private getCacheView(uiClass: FguiClass, zOrder: number = ViewZOrder.UI, callback?: Function, intent?: any): boolean { const viewKey = uiClass.getViewName(); if (this._closed.ContainsKey(viewKey)) { const uiview = this._closed.Value(viewKey); if (uiview.viewType == ViewType.Full) { this._opened.Foreach((key: string, value: FguiView) => { if (value.viewType != ViewType.Part && value.zOrder <= uiview.zOrder) { value.addFullHideCount(1); } }) } this._closed.Remove(viewKey); this._opened.Add(viewKey, uiview); this.AddPanel(uiview.Panel, zOrder); uiview.show(intent); uiview.zOrder = zOrder; uiview.uiPkgName = uiClass.getPkgName(); //回调 callback && callback(uiview); return true; } return false; } private CreateView(uiClass: FguiClass, zOrder: number = ViewZOrder.UI, intent?: any, complete?: Function) { let handler = new fgui.AsyncOperation(); handler.callback = async (gObject) => { if (this._opened.ContainsKey(uiClass.getViewName())) { EventMng.emit(GUIEvent.SHOW_MASK, uiClass.getPkgName(), false) console.error(`FguiMgr::Open ${uiClass.getViewName()} has already opened.`); return; } let panel = gObject as fgui.GComponent; if (panel == null) { EventMng.emit(GUIEvent.SHOW_MASK, uiClass.getPkgName(), false) console.error(`FguiMgr createObject[${uiClass.getViewName}] error: GObject为空.`); return; } panel.node.name = uiClass.getPrefabName(); let uiview = new uiClass(); uiview.zOrder = zOrder; uiview.uiPkgName = uiClass.getPkgName(); uiview.initForward(panel, null); const resKeeper = ResKeeper.Get(panel.node, true); let resCollector = new ResCollector(); uiview.Controller.onCollectRes(resCollector, intent); if (resCollector.GetResList().length > 0) { await resKeeper.LoadResCollector(resCollector, PromiseDefault); } if (uiview.viewType == ViewType.Full) { this._opened.Foreach((key: string, value: FguiView) => { if (value.viewType != ViewType.Part && value.zOrder <= uiview.zOrder) { value.addFullHideCount(1); } }) } this._opened.Add(uiClass.getViewName(), uiview); uiview.init(); this.AddPanel(panel, zOrder); uiview.show(intent); this.AddPkgCount(uiClass.getPkgName(), uiClass.getViewName()); EventMng.emit(GUIEvent.SHOW_MASK, uiClass.getPkgName(), false) complete && complete(uiview); }; handler.createObject(uiClass.getPkgName(), uiClass.getPrefabName()); } /** * @param isDispose 是否销毁 */ public closeUI(uiClass: FguiClass, isDispose: boolean = false) { const viewKey = uiClass.getViewName(); if (this._opened.ContainsKey(viewKey)) { const view = this._opened.Value(viewKey); this._opened.Remove(viewKey); view.hide(isDispose); this.RemovePanel(view.Panel); if (isDispose) { this.DestroyView(view, uiClass); } else { this._closed.Add(viewKey, view); } if (view.viewType == ViewType.Full) { this._opened.Foreach((key: string, value: FguiView) => { if (value.viewType != ViewType.Part && value.zOrder <= view.zOrder) { value.addFullHideCount(-1); } }) } } else if (isDispose && this._closed.ContainsKey(viewKey)) { const view = this._closed.Value(viewKey); this._closed.Remove(viewKey); this.DestroyView(view, uiClass); } } // 判断界面是否打开 public isShowing(uiClass: FguiClass) { const viewKey = uiClass?.getViewName(); if (this._opened.ContainsKey(viewKey)) { return true } return false } // 获取打开的界面 public getShowingView(uiClass: FguiClass) { const viewKey = uiClass?.getViewName(); if (this._opened.ContainsKey(viewKey)) { const view = this._opened.Value(viewKey); return view } return null } /** * 当前是否有除了指定页面以外的其他页面被打开 */ public checkOtherUIOpen(uilist: FguiClass[]) { let list = [] for (let i of uilist) { list.push(i.getViewName()) } let haveother: boolean = false this._opened.Foreach((key: string, value: FguiView) => { if (list.indexOf(key) < 0) { haveother = true } }) return haveother } public isShowingByName(uiViewName: string) { return this._opened.ContainsKey(uiViewName); } // 获取打开的界面 public getShowingViewByName(uiViewName: string) { if (this._opened.ContainsKey(uiViewName)) { const view = this._opened.Value(uiViewName); return view } return null } public findNodeByName(uiViewName: string, goName: string): cc.Node { if (this._opened.ContainsKey(uiViewName)) { let view = this._opened.Value(uiViewName); let goNames = goName.split("/") let go = null let goTemp = view["_viewModel"][goNames[0]]; if (gameMethod.isEmpty(goTemp)) { goTemp = view.Panel.getChild(goNames[0]); } for (let i = 1; i < goNames.length; i++) { if (goTemp?.Panel) { goTemp = goTemp.Panel?.getChild(goNames[i]) } else { goTemp = goTemp?.getChild(goNames[i]); } } go = goTemp if (!gameMethod.isEmpty(go)) { go.visible = true } else { console.error(`界面:${uiViewName} 找不到目标节点: ${goNames}`) } return go?.node ?? null; } return null; } public removePkg(uiClass: FguiClass) { if (!this._addPkged.ContainsKey(uiClass.getPkgName()) || this._addPkged.Value(uiClass.getPkgName()) == 0) { fgui.UIPackage.removePackage(uiClass.getPkgName()) } else { console.warn("removePkg fail") } } public clearOpenUI() { this._opened.Foreach((viewKey: string, value: FguiView) => { value.hide(); this.RemovePanel(value.Panel); this._closed.Add(viewKey, value); }) this._opened.Clear() } public clearAllUI() { this._opened.Foreach((viewKey: string, value: FguiView) => { value.hide(); this.RemovePanel(value.Panel); }) this.clearCacheMap() // this._addPkged.Foreach((pkgName: string, value: number) => { // fgui.UIPackage.removePackage(pkgName) // }) this._addPkged.Clear(); } public clearCacheMap() { this._opened.Clear() this._closed.Clear() } OnUpdate(elapseTime: number): void { this._opened.Foreach((k, v) => { v.OnUpdate(elapseTime); }, this); } OnLateUpdate(elapseTime: number): void { this._opened.Foreach((k, v) => { v.OnLateUpdate(elapseTime); }, this); } Dispose(): void { //TODO 有需要再补充 } /** 增加fgui pkg计数 */ public AddPkgCount(pkgName: string, from?: string) { if (this._addPkged.ContainsKey(pkgName)) { //已存在++ let pkgCount = this._addPkged.Value(pkgName); pkgCount++; this._addPkged.Replace(pkgName, pkgCount) } else { this._addPkged.Add(pkgName, 1) } if (!gameMethod.isEmpty(GameDataCenter?.login.playerInfo?.switch?.clientLog)) { console.log(`${from} ${pkgName} count: ${this._addPkged.Value(pkgName)}`) } } /** 减少fgui pkg计数 */ public DelPkgCount(pkgName: string, from?: string) { if (this._addPkged.ContainsKey(pkgName)) { //已存在++ let pkgCount = this._addPkged.Value(pkgName); pkgCount--; if (!gameMethod.isEmpty(GameDataCenter?.login.playerInfo?.switch?.clientLog)) { console.log(`${pkgName} count: ${pkgCount}`, from) } this._addPkged.Replace(pkgName, pkgCount); if (pkgCount <= 0 && pkgName != "Common") { if (!gameMethod.isEmpty(GameDataCenter?.login.playerInfo?.switch?.clientLog)) { console.log(`removePackage:${pkgName}`, from) } fgui.UIPackage.removePackage(pkgName) } } } AddPkgByPkgName(pkgName: string, cb?: Function) { if (fgui.UIPackage.getByName(pkgName) == null) { // 加载uipackage FguiLoadMgr.loadPackage(pkgName, pkgName, (error, pkg) => { if (error) { EventMng.emit(GUIEvent.SHOW_MASK, pkgName, false) console.error(`FguiMgr LoadPackage[${pkgName}] error: ${error}`); return; } this.AddPkgCount(pkgName); if (!gameMethod.isEmpty(GameDataCenter?.login.playerInfo?.switch?.clientLog)) { console.log(`${pkgName} count: ${this._addPkged.Value(pkgName)}`) } cb && cb(); }); } else { this.AddPkgCount(pkgName); if (!gameMethod.isEmpty(GameDataCenter?.login.playerInfo?.switch?.clientLog)) { console.log(`${pkgName} count: ${this._addPkged.Value(pkgName)}`) } cb && cb(); } } RemovePkgByPkgName(pkgName: string) { //ios平台才释放,安卓平台不释放 if (GameDataCenter.plat.instance.deviceOS != PlatFormDevType.iosH5 && GameDataCenter.plat.instance.deviceOS != PlatFormDevType.ios && GameDataCenter.plat.instance.deviceOS != PlatFormDevType.local) { return; } this.DelPkgCount(pkgName); } private AddPanel(panel: fgui.GComponent, zOrder: ViewZOrder) { const layerNode = this._layerNodeMap.get(zOrder); if (layerNode) { layerNode.addChild(panel); } else { fgui.GRoot.inst.addChild(panel); } // UI全屏自适应 panel.makeFullScreen(); } private RemovePanel(panel: fgui.GComponent) { fgui.GRoot.inst.removeChild(panel); } private DestroyView(uiview: FguiView, uiClass: FguiClass) { //ios平台才释放,安卓平台不释放 if (GameDataCenter.plat.instance.deviceOS != PlatFormDevType.iosH5 && GameDataCenter.plat.instance.deviceOS != PlatFormDevType.ios && GameDataCenter.plat.instance.deviceOS != PlatFormDevType.local) { return; } var panel = uiview.Panel; panel.dispose(); this.DelPkgCount(uiClass.getPkgName()); } public CloseUIByLayer(zOrder: ViewZOrder) { this._opened.Foreach((viewKey: string, value: FguiView) => { if (value.zOrder == zOrder) { const view = this._opened.Value(viewKey); this._opened.Remove(viewKey); view.hide(); this.RemovePanel(view.Panel); this._closed.Add(viewKey, view); if (view.viewType == ViewType.Full) { this._opened.Foreach((key: string, value: FguiView) => { if (value.viewType != ViewType.Part && value.zOrder <= view.zOrder) { value.addFullHideCount(-1); } }) } } }) } /** 关闭所有的UI elseView 排除无需关闭的界面 */ public CloseAllUI(elseView: string[] = []): void { this._opened.Foreach((viewKey: string, value: FguiView) => { if (elseView.indexOf(viewKey) < 0) { const view = this._opened.Value(viewKey); this._opened.Remove(viewKey); view.hide(); this.RemovePanel(view.Panel); this._closed.Add(viewKey, view); if (view.viewType == ViewType.Full) { this._opened.Foreach((key: string, value: FguiView) => { if (value.viewType != ViewType.Part && value.zOrder <= view.zOrder) { value.addFullHideCount(-1); } }) } } }) } //#endregion }