import { instantiate, Node, Prefab, Widget } from "cc"; import { oops } from "../../Oops"; import { UICallbacks, ViewParams } from "./Defines"; import { DelegateComponent } from "./DelegateComponent"; import { UIConfig } from "./LayerManager"; /** 界面层对象 */ export class LayerUI extends Node { /** 显示界面节点集合 */ protected ui_nodes = new Map(); /** 被移除的界面缓存数据 */ protected ui_cache = new Map(); /** * UI基础层,允许添加多个预制件节点 * @param name 该层名 * @param container 容器Node */ constructor(name: string) { super(name); var widget: Widget = this.addComponent(Widget); widget.isAlignLeft = widget.isAlignRight = widget.isAlignTop = widget.isAlignBottom = true; widget.left = widget.right = widget.top = widget.bottom = 0; widget.alignMode = 2; widget.enabled = true; } /** * 添加一个预制件节点到层容器中,该方法将返回一个唯一`uuid`来标识该操作节点 * @param prefabPath 预制件路径 * @param params 自定义参数 * @param callbacks 回调函数对象,可选 * @returns ture为成功,false为失败 */ add(config: UIConfig, params?: any, callbacks?: UICallbacks) { if (this.ui_nodes.has(config.prefab)) { console.warn(`路径为【${config.prefab}】的预制重复加载`); return; } // 检查缓存中是否存界面 var vp = this.ui_cache.get(config.prefab); if (vp == null) { vp = new ViewParams(); vp.config = config; } this.ui_nodes.set(config.prefab, vp); vp.params = params ?? {}; vp.callbacks = callbacks ?? {}; vp.valid = true; this.load(vp, config.bundle) } /** * 加载界面资源 * @param vp 显示参数 * @param bundle 远程资源包名,如果为空就是默认本地资源包 */ protected load(vp: ViewParams, bundle?: string) { if (vp && vp.node) { this.showUi(vp); } else { // 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源 bundle = bundle || oops.res.defaultBundleName; oops.res.load(bundle, vp.config.prefab, (err: Error | null, res: Prefab) => { if (err) { this.ui_nodes.delete(vp.config.prefab); console.warn(`路径为【${vp.config.prefab}】的预制加载失败`); vp.callbacks && vp.callbacks.onLoadFailure && vp.callbacks.onLoadFailure(); return; } let childNode: Node = instantiate(res); vp.node = childNode; let comp = childNode.addComponent(DelegateComponent); comp.vp = vp; comp.onCloseWindow = this.onCloseWindow.bind(this); this.showUi(vp); }); } } protected onCloseWindow(vp: ViewParams) { this.ui_nodes.delete(vp.config.prefab); } /** * 创建界面节点 * @param vp 视图参数 */ protected showUi(vp: ViewParams) { // 触发窗口添加事件 let comp = vp.node.getComponent(DelegateComponent)!; comp.add(); vp.node.parent = this; // 标记界面为使用状态 vp.valid = true; } /** * 根据预制件路径删除,预制件如在队列中也会被删除,如果该预制件存在多个也会一起删除 * @param prefabPath 预制路径 * @param isDestroy 移除后是否释放 */ remove(prefabPath: string, isDestroy?: boolean): void { var release = undefined; if (isDestroy !== undefined) release = isDestroy; // 界面移出舞台 var vp = this.ui_nodes.get(prefabPath); if (vp) { // // 优先使用参数中控制的释放条件,如果未传递参数则用配置中的释放条件 // if (release === undefined && vp.config.destroy !== undefined) { // release = vp.config.destroy; // } // // 默认不缓存关闭的界面 // else { // release = true; // } // 优先使用参数中控制的释放条件,如果未传递参数则用配置中的释放条件,默认不缓存关闭的界面 if (release === undefined) { release = vp.config.destroy !== undefined ? vp.config.destroy : true; } // 不释放界面,缓存起来待下次使用 if (release === false) { this.ui_cache.set(vp.config.prefab, vp); } var childNode = vp.node; var comp = childNode.getComponent(DelegateComponent)!; comp.remove(release); } // 验证是否删除后台缓存界面 if (release === true) this.removeCache(prefabPath); } /** 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面 */ private removeCache(prefabPath: string) { let vp = this.ui_cache.get(prefabPath); if (vp) { this.ui_nodes.delete(vp.config.prefab); this.ui_cache.delete(prefabPath); var childNode = vp.node; childNode.destroy(); } } /** * 根据预制路径获取已打开界面的节点对象 * @param prefabPath 预制路径 */ get(prefabPath: string): Node { var vp = this.ui_nodes.get(prefabPath); if (vp) return vp.node; return null!; } /** * 判断当前层是否包含 uuid或预制件路径对应的Node节点 * @param prefabPath 预制件路径或者UUID */ has(prefabPath: string): boolean { return this.ui_nodes.has(prefabPath); } /** * 清除所有节点,队列当中的也删除 * @param isDestroy 移除后是否释放 */ clear(isDestroy: boolean): void { // 清除所有显示的界面 this.ui_nodes.forEach((value: ViewParams, key: string) => { this.remove(value.config.prefab, isDestroy); value.valid = false; }); this.ui_nodes.clear(); // 清除缓存中的界面 if (isDestroy) { this.ui_cache.forEach((value: ViewParams, prefabPath: string) => { this.removeCache(prefabPath); }); } } }