mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-05-09 03:46:04 +08:00
217 lines
7.4 KiB
TypeScript
217 lines
7.4 KiB
TypeScript
import { instantiate, Node, Prefab, SafeArea, Widget } from "cc";
|
||
import { Collection } from "db://oops-framework/libs/collection/Collection";
|
||
import { oops } from "../../Oops";
|
||
import { UICallbacks, ViewParams } from "./Defines";
|
||
import { DelegateComponent } from "./DelegateComponent";
|
||
import { UIConfig } from "./LayerManager";
|
||
|
||
/** 界面层对象 */
|
||
export class LayerUI extends Node {
|
||
/** 全局窗口打开失败 */
|
||
onOpenFailure: Function = null!;
|
||
/** 显示界面节点集合 */
|
||
protected ui_nodes = new Collection<string, ViewParams>();
|
||
/** 被移除的界面缓存数据 */
|
||
protected ui_cache = new Map<string, ViewParams>();
|
||
|
||
/**
|
||
* UI基础层,允许添加多个预制件节点
|
||
* @param name 该层名
|
||
*/
|
||
constructor(name: string) {
|
||
super(name);
|
||
|
||
const 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 config 界面配置数据
|
||
* @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;
|
||
}
|
||
|
||
// 检查缓存中是否存界面
|
||
let 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 async load(vp: ViewParams, bundle?: string) {
|
||
// 加载界面资源超时提示
|
||
const timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
|
||
|
||
if (vp && vp.node) {
|
||
await this.showUi(vp);
|
||
}
|
||
else {
|
||
// 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源
|
||
bundle = bundle || oops.res.defaultBundleName;
|
||
const res = await oops.res.loadAsync(bundle, vp.config.prefab, Prefab);
|
||
if (res) {
|
||
vp.node = instantiate(res);
|
||
// 是否启动真机安全区域显示
|
||
if (vp.config.safeArea) vp.node.addComponent(SafeArea);
|
||
|
||
// 窗口事件委托
|
||
const dc = vp.node.addComponent(DelegateComponent);
|
||
dc.vp = vp;
|
||
dc.onCloseWindow = this.onCloseWindow.bind(this);
|
||
|
||
// 显示界面
|
||
await this.showUi(vp);
|
||
}
|
||
else {
|
||
console.warn(`路径为【${vp.config.prefab}】的预制加载失败`);
|
||
this.failure(vp);
|
||
}
|
||
}
|
||
|
||
// 关闭界面资源超时提示
|
||
oops.gui.waitClose();
|
||
clearTimeout(timerId);
|
||
}
|
||
|
||
/** 加载超时事件*/
|
||
private onLoadingTimeoutGui() {
|
||
oops.gui.waitOpen();
|
||
}
|
||
|
||
/** 窗口关闭事件 */
|
||
protected onCloseWindow(vp: ViewParams) {
|
||
this.ui_nodes.delete(vp.config.prefab);
|
||
}
|
||
|
||
/**
|
||
* 创建界面节点
|
||
* @param vp 视图参数
|
||
*/
|
||
protected async showUi(vp: ViewParams): Promise<boolean> {
|
||
// 触发窗口添加事件
|
||
const comp = vp.node.getComponent(DelegateComponent)!;
|
||
const r: boolean = await comp.add();
|
||
if (r) {
|
||
vp.node.parent = this;
|
||
|
||
// 标记界面为使用状态
|
||
vp.valid = true;
|
||
}
|
||
else {
|
||
console.warn(`路径为【${vp.config.prefab}】的自定义预处理逻辑异常.检查预制上绑定的组件中 onAdded 方法,返回true才能正确完成窗口显示流程`);
|
||
this.failure(vp);
|
||
}
|
||
return r;
|
||
}
|
||
|
||
/** 打开窗口失败逻辑 */
|
||
protected failure(vp: ViewParams) {
|
||
this.onCloseWindow(vp);
|
||
vp.callbacks && vp.callbacks.onLoadFailure && vp.callbacks.onLoadFailure();
|
||
this.onOpenFailure && this.onOpenFailure();
|
||
}
|
||
|
||
/**
|
||
* 根据预制件路径删除,预制件如在队列中也会被删除,如果该预制件存在多个也会一起删除
|
||
* @param prefabPath 预制路径
|
||
* @param isDestroy 移除后是否释放
|
||
*/
|
||
remove(prefabPath: string, isDestroy?: boolean): void {
|
||
let release: any = undefined;
|
||
if (isDestroy !== undefined) release = isDestroy;
|
||
|
||
// 界面移出舞台
|
||
const vp = this.ui_nodes.get(prefabPath);
|
||
if (vp) {
|
||
// 优先使用参数中控制的释放条件,如果未传递参数则用配置中的释放条件,默认不缓存关闭的界面
|
||
if (release === undefined) {
|
||
release = vp.config.destroy !== undefined ? vp.config.destroy : true;
|
||
}
|
||
|
||
// 不释放界面,缓存起来待下次使用
|
||
if (release === false) {
|
||
this.ui_cache.set(vp.config.prefab, vp);
|
||
}
|
||
|
||
const childNode = vp.node;
|
||
const 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.onCloseWindow(vp);
|
||
this.ui_cache.delete(prefabPath);
|
||
const childNode = vp.node;
|
||
childNode.destroy();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 根据预制路径获取已打开界面的节点对象
|
||
* @param prefabPath 预制路径
|
||
*/
|
||
get(prefabPath: string): Node {
|
||
const 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);
|
||
});
|
||
}
|
||
}
|
||
} |