重构GUI模块打开界面与关闭界面的参数,方便后续扩展新功能,而保持接口不变

This commit is contained in:
dgflash
2025-09-10 18:35:44 +08:00
parent 22888a17ec
commit 92e8ccbe9b
10 changed files with 265 additions and 388 deletions

View File

@@ -4,9 +4,9 @@
* @LastEditors: dgflash
* @LastEditTime: 2023-07-24 17:14:57
*/
import { Node } from "cc";
import { LayerPopUp } from "./LayerPopup";
import { UICallbacks, UIParams } from "./LayerUIElement";
import { UIParam, UIState } from "./LayerUIElement";
import { UIConfig } from "./UIConfig";
/** 模式弹窗数据 */
@@ -16,9 +16,7 @@ type DialogParam = {
/** 窗口配置 */
config: UIConfig;
/** 窗口附加参数 */
params?: any;
/** 窗口回调 */
callbacks?: UICallbacks;
params?: UIParam;
}
/*
@@ -27,54 +25,55 @@ type DialogParam = {
export class LayerDialog extends LayerPopUp {
/** 窗口调用参数队列 */
private params: Array<DialogParam> = [];
/** 当前打开的界面 */
private current: Node = null!;
add(uiid: string, config: UIConfig, params?: any, callbacks?: UICallbacks) {
// 控制同一时间只能显示一个模式窗口
if (this.ui_nodes.size > 0) {
this.params.push({
uiid: uiid,
config: config,
params: params,
callbacks: callbacks,
});
return;
}
this.show(uiid, config, params, callbacks);
/**
* 添加模式窗口
* 1. 同时添加多个模式窗口时,第一个之后的窗口会先队列起来,在第一个关闭后在加载与显示第二个;同时方法返回节点保持只返回当前显示的界面节点
*/
add(uiid: string, config: UIConfig, params?: UIParam): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
// 控制同一时间只能显示一个模式窗口
if (this.ui_nodes.size > 0) {
this.params.push({
uiid: uiid,
config: config,
params: params
});
resolve(this.current);
}
else {
this.current = await this.showDialog(uiid, config, params);
resolve(this.current);
}
});
}
/** 显示模式弹窗 */
private show(uiid: string, config: UIConfig, params?: any, callbacks?: UICallbacks) {
let uip = this.ui_cache.get(config.prefab);
if (uip == null) {
uip = new UIParams();
uip.uiid = uiid;
uip.valid = true;
uip.config = config;
}
uip.params = params || {};
uip.callbacks = callbacks ?? {};
this.ui_nodes.set(uip.config.prefab, uip);
this.load(uip, config.bundle);
private showDialog(uiid: string, config: UIConfig, param?: UIParam): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
let state = this.initUIConfig(uiid, config, param);
let node = await this.load(state, config.bundle);
resolve(node);
});
}
protected onCloseWindow(uip: UIParams) {
super.onCloseWindow(uip);
protected uiClose(state: UIState) {
super.uiClose(state);
setTimeout(this.next.bind(this), 0);
}
protected closeUI() {
protected closeBlack() {
if (this.params.length == 0) {
super.closeUI();
super.closeBlack();
}
}
private next() {
if (this.params.length > 0) {
let param = this.params.shift()!;
this.show(param.uiid, param.config, param.params, param.callbacks);
this.showDialog(param.uiid, param.config, param.params);
}
}
}

View File

@@ -9,7 +9,7 @@ import { LayerHelper } from "./LayerHelper";
import { LayerNotify } from "./LayerNotify";
import { LayerPopUp } from "./LayerPopup";
import { LayerUI } from "./LayerUI";
import { LayerUIElement, UICallbacks } from "./LayerUIElement";
import { LayerUIElement, UIParam } from "./LayerUIElement";
import { UIConfig } from "./UIConfig";
/** 界面层级管理器 */
@@ -171,13 +171,13 @@ export class LayerManager {
this.notify.waitClose();
}
/** 获取界面信息 */
private getInfo(uiid: Uiid): { key: string; config: UIConfig } {
let key = "";
let config: UIConfig = null!;
// 界面配置
if (typeof uiid === 'object') {
if (uiid.bundle == null) uiid.bundle = resLoader.defaultBundleName;
key = uiid.bundle + "_" + uiid.prefab;
config = gui.internal.getConfig(key);
if (config == null) {
@@ -205,8 +205,7 @@ export class LayerManager {
/**
* 同步打开一个窗口
* @param uiid 窗口唯一编号
* @param uiArgs 窗口参数
* @param callbacks 回调对象
* @param param 窗口参数
* @example
var uic: UICallbacks = {
onAdded: (node: Node, params: any) => {
@@ -218,50 +217,43 @@ export class LayerManager {
};
oops.gui.open(UIID.Loading, null, uic);
*/
open(uiid: Uiid, uiArgs: any = null, callbacks?: UICallbacks): void {
open(uiid: Uiid, param?: UIParam): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
let info = this.getInfo(uiid);
let layer = this.uiLayers.get(info.config.layer);
if (layer) {
let node = await layer.add(info.key, info.config, param);
resolve(node);
}
else {
console.error(`打开编号为【${uiid}】的界面失败,界面层不存在`);
}
});
}
/** 显示指定界面 */
show(uiid: Uiid) {
let info = this.getInfo(uiid);
let layer = this.uiLayers.get(info.config.layer);
if (layer) {
layer.add(info.key, info.config, uiArgs, callbacks);
layer.show(info.config.prefab);
}
else {
console.error(`打开编号为【${uiid}】的界面失败,界面层不存在`);
}
}
/**
* 异步打开一个窗口
* @param uiid 窗口唯一编号
* @param uiArgs 窗口参数
* @example
* var node = await oops.gui.openAsync(UIID.Loading);
*/
async openAsync(uiid: Uiid, uiArgs: any = null): Promise<Node | null> {
return new Promise<Node | null>((resolve, reject) => {
const callbacks: UICallbacks = {
onAdded: (node: Node, params: any) => {
resolve(node);
},
onLoadFailure: () => {
resolve(null);
}
};
this.open(uiid, uiArgs, callbacks);
});
}
/**
* 移除指定标识的窗口
* @param uiid 窗口唯一标识
* @param isDestroy 移除后是否释放(默认释放内存)
* @example
* oops.gui.remove(UIID.Loading);
*/
remove(uiid: Uiid, isDestroy: boolean = true) {
remove(uiid: Uiid) {
let info = this.getInfo(uiid);
let layer = this.uiLayers.get(info.config.layer);
if (layer) {
layer.remove(info.config.prefab, isDestroy);
layer.remove(info.config.prefab);
}
else {
console.error(`移除编号为【${uiid}】的界面失败,界面层不存在`);
@@ -271,25 +263,24 @@ export class LayerManager {
/**
* 通过界面节点移除
* @param node 窗口节点
* @param isDestroy 移除后是否释放资源(默认释放内存)
* @example
* oops.gui.removeByNode(cc.Node);
*/
removeByNode(node: Node, isDestroy: boolean = true) {
removeByNode(node: Node) {
if (node instanceof Node) {
let comp = node.getComponent(LayerUIElement);
if (comp && comp.params) {
if (comp && comp.state) {
// 释放显示的界面
if (node.parent) {
let uiid = gui.internal.getConfig(comp.params.uiid);
this.remove(uiid, isDestroy);
let uiid = gui.internal.getConfig(comp.state.uiid);
this.remove(uiid);
}
// 释放缓存中的界面
else if (isDestroy) {
let layer = this.uiLayers.get(comp.params.config.layer);
else {
let layer = this.uiLayers.get(comp.state.config.layer);
if (layer) {
// @ts-ignore 注:不对外使用
layer.removeCache(comp.params.config.prefab);
layer.removeCache(comp.state.config.prefab);
}
}
}
@@ -303,34 +294,14 @@ export class LayerManager {
/**
* 场景替换
* @param removeUiId 移除场景编号
* @param openUiId 新打开场景编号
* @param uiArgs 新打开场景参数
* @param openUiid 新打开场景编号
* @param param 新打开场景参数
*/
replace(removeUiId: Uiid, openUiId: Uiid, uiArgs: any = null) {
const callbacks: UICallbacks = {
onAdded: (node: Node, params: any) => {
this.remove(removeUiId);
}
};
this.open(openUiId, uiArgs, callbacks);
}
/**
* 异步场景替换
* @param removeUiId 移除场景编号
* @param openUiId 新打开场景编号
* @param uiArgs 新打开场景参数
*/
replaceAsync(removeUiId: Uiid, openUiId: Uiid, uiArgs: any = null): Promise<Node | null> {
return new Promise<Node | null>(async (resolve, reject) => {
const node = await this.openAsync(openUiId, uiArgs);
if (node) {
this.remove(removeUiId);
resolve(node);
}
else {
resolve(null);
}
replace(removeUiId: Uiid, openUiid: Uiid, param?: UIParam): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
let node = await this.open(openUiid, param);
this.remove(removeUiId);
resolve(node);
});
}

View File

@@ -7,7 +7,7 @@ import { BlockInputEvents, EventTouch, Node } from "cc";
import { ViewUtil } from "../../utils/ViewUtil";
import { PromptResType } from "../GuiEnum";
import { LayerUI } from "./LayerUI";
import { UIParams } from "./LayerUIElement";
import { UIState } from "./LayerUIElement";
import { UIConfig } from "./UIConfig";
/* 弹窗层,允许同时弹出多个窗口 */
@@ -32,12 +32,12 @@ export class LayerPopUp extends LayerUI {
if (this.mask) this.mask.setSiblingIndex(this.children.length - 2);
}
protected showUi(uip: UIParams): Promise<boolean> {
protected uiInit(state: UIState): Promise<boolean> {
return new Promise(async (resolve) => {
const r = await super.showUi(uip);
const r = await super.uiInit(state);
if (r) {
// 界面加载完成显示时,启动触摸非窗口区域关闭
this.openVacancyRemove(uip.config);
this.openVacancyRemove(state.config);
// 界面加载完成显示时,层级事件阻挡
this.black.enabled = true;
@@ -46,15 +46,15 @@ export class LayerPopUp extends LayerUI {
});
}
protected onCloseWindow(uip: UIParams) {
super.onCloseWindow(uip);
protected uiClose(state: UIState) {
super.uiClose(state);
// 界面关闭后,关闭触摸事件阻挡、关闭触摸非窗口区域关闭、关闭遮罩
this.closeUI();
this.closeBlack();
}
/** 设置触摸事件阻挡 */
protected closeUI() {
protected closeBlack() {
// 所有弹窗关闭后,关闭事件阻挡功能
if (this.ui_nodes.size == 0) {
if (this.black) this.black.enabled = false;
@@ -120,13 +120,13 @@ export class LayerPopUp extends LayerUI {
if (this.ui_nodes.size > 0) {
let vp = this.ui_nodes.array[this.ui_nodes.size - 1];
if (vp.valid && vp.config.vacancy) {
this.remove(vp.config.prefab, vp.config.destroy);
this.remove(vp.config.prefab);
}
}
}
clear(isDestroy: boolean) {
super.clear(isDestroy)
this.closeUI();
this.closeBlack();
}
}

View File

@@ -1,19 +1,20 @@
import { instantiate, Node, Prefab, SafeArea } from "cc";
import { Collection } from "db://oops-framework/libs/collection/Collection";
import { resLoader } from "../../common/loader/ResLoader";
import { oops } from "../../Oops";
import { Uiid } from "./LayerEnum";
import { LayerHelper } from "./LayerHelper";
import { LayerUIElement, UICallbacks, UIParams } from "./LayerUIElement";
import { LayerUIElement, UIParam, UIState } from "./LayerUIElement";
import { UIConfig } from "./UIConfig";
/** 界面层对象 */
export class LayerUI extends Node {
/** 全局窗口打开失败 */
/** 全局窗口打开失败事件 */
onOpenFailure: Function = null!;
/** 显示界面节点集合 */
protected ui_nodes = new Collection<string, UIParams>();
protected ui_nodes = new Collection<string, UIState>();
/** 被移除的界面缓存数据 */
protected ui_cache = new Map<string, UIParams>();
protected ui_cache = new Map<string, UIState>();
/**
* UI基础层允许添加多个预制件节点
@@ -28,71 +29,101 @@ export class LayerUI extends Node {
* 添加一个预制件节点到层容器中,该方法将返回一个唯一`uuid`来标识该操作节点
* @param config 界面配置数据
* @param params 自定义参数
* @param callbacks 回调函数对象,可选
* @returns ture为成功,false为失败
*/
add(uiid: Uiid, config: UIConfig, params?: any, callbacks?: UICallbacks) {
if (this.ui_nodes.has(config.prefab)) {
console.warn(`路径为【${config.prefab}】的预制重复加载`);
return;
add(uiid: Uiid, config: UIConfig, params?: UIParam): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
if (this.ui_nodes.has(config.prefab)) {
console.warn(`路径为【${config.prefab}】的预制重复加载`);
return;
}
// 检查缓存中是否存界面
let state = this.initUIConfig(uiid, config, params);
await this.load(state, config.bundle);
resolve(state.node);
});
}
/** 初始化界面配置初始值 */
protected initUIConfig(uiid: Uiid, config: UIConfig, params?: UIParam) {
let state = this.ui_cache.get(config.prefab);
if (state == null) {
if (config.bundle == null) config.bundle = resLoader.defaultBundleName;
if (config.destroy == null) config.destroy = true;
if (config.vacancy == null) config.vacancy = false;
if (config.mask == null) config.mask = false;
if (config.safeArea == null) config.safeArea = false;
state = new UIState();
state.uiid = uiid.toString();
state.config = config;
}
// 检查缓存中是否存界面
let uip = this.ui_cache.get(config.prefab);
if (uip == null) {
uip = new UIParams();
uip.uiid = uiid.toString();
uip.config = config;
}
this.ui_nodes.set(config.prefab, uip);
uip.params = params ?? {};
uip.callbacks = callbacks ?? {};
uip.valid = true;
this.load(uip, config.bundle)
state.params = params ?? {};
state.valid = true;
this.ui_nodes.set(config.prefab, state);
return state;
}
/**
* 加载界面资源
* @param uip 显示参数
* @param state 显示参数
* @param bundle 远程资源包名,如果为空就是默认本地资源包
*/
protected async load(uip: UIParams, bundle?: string) {
// 加载界面资源超时提示
const timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
protected async load(state: UIState, bundle: string = resLoader.defaultBundleName): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
// 加载界面资源超时提示
let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
if (state.node == null) {
// 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源
const res = await resLoader.loadAsync(bundle, state.config.prefab, Prefab);
if (res) {
state.node = instantiate(res);
if (uip && uip.node) {
await this.showUi(uip);
}
else {
// 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源
bundle = bundle || oops.res.defaultBundleName;
const res = await oops.res.loadAsync(bundle, uip.config.prefab, Prefab);
if (res) {
uip.node = instantiate(res);
// 是否启动真机安全区域显示
if (state.config.safeArea) state.node.addComponent(SafeArea);
// 是否启动真机安全区域显示
if (uip.config.safeArea) uip.node.addComponent(SafeArea);
// 窗口事件委托
const comp = state.node.addComponent(LayerUIElement);
comp.state = state;
}
else {
console.warn(`路径为【${state.config.prefab}】的预制加载失败`);
this.failure(state);
}
}
// 窗口事件委托
const dc = uip.node.addComponent(LayerUIElement);
dc.params = uip;
//@ts-ignore
dc.onCloseWindow = this.onCloseWindow.bind(this);
// 关闭界面资源超时提示
oops.gui.waitClose();
clearTimeout(timerId);
// 显示界面
await this.showUi(uip);
await this.uiInit(state);
resolve(state.node);
});
}
/**
* 创建界面节点
* @param state 视图参数
*/
protected uiInit(state: UIState): Promise<boolean> {
return new Promise<boolean>(async (resolve, reject) => {
const comp = state.node.getComponent(LayerUIElement)!;
const r: boolean = await comp.add();
if (r) {
state.valid = true; // 标记界面为使用状态
if (!state.params.preload) {
state.params.preload = false;
state.node.parent = this;
}
}
else {
console.warn(`路径为【${uip.config.prefab}】的预制加载失败`);
this.failure(uip);
console.warn(`路径为【${state.config.prefab}】的自定义预处理逻辑异常.检查预制上绑定的组件中 onAdded 方法,返回true才能正确完成窗口显示流程`);
this.failure(state);
}
}
// 关闭界面资源超时提示
oops.gui.waitClose();
clearTimeout(timerId);
resolve(r);
});
}
/** 加载超时事件*/
@@ -101,74 +132,52 @@ export class LayerUI extends Node {
}
/** 窗口关闭事件 */
protected onCloseWindow(vp: UIParams) {
this.ui_nodes.delete(vp.config.prefab);
}
/**
* 创建界面节点
* @param uip 视图参数
*/
protected async showUi(uip: UIParams): Promise<boolean> {
// 触发窗口添加事件
const comp = uip.node.getComponent(LayerUIElement)!;
const r: boolean = await comp.add();
if (r) {
uip.node.parent = this;
// 标记界面为使用状态
uip.valid = true;
}
else {
console.warn(`路径为【${uip.config.prefab}】的自定义预处理逻辑异常.检查预制上绑定的组件中 onAdded 方法,返回true才能正确完成窗口显示流程`);
this.failure(uip);
}
return r;
protected uiClose(state: UIState) {
this.ui_nodes.delete(state.config.prefab);
}
/** 打开窗口失败逻辑 */
protected failure(uip: UIParams) {
this.onCloseWindow(uip);
uip.callbacks && uip.callbacks.onLoadFailure && uip.callbacks.onLoadFailure();
protected failure(state: UIState) {
this.uiClose(state);
this.onOpenFailure && this.onOpenFailure();
}
/**
* 根据预制件路径删除,预制件如在队列中也会被删除,如果该预制件存在多个也会一起删除
* @param prefabPath 预制路径
* @param isDestroy 移除后是否释放
*/
remove(prefabPath: string, isDestroy?: boolean): void {
let release: any = undefined;
if (isDestroy !== undefined) release = isDestroy;
remove(prefabPath: string): void {
let release: boolean = true;
// 界面移出舞台
const uip = this.ui_nodes.get(prefabPath);
if (uip) {
const state = this.ui_nodes.get(prefabPath);
if (state) {
// 优先使用参数中控制的释放条件,如果未传递参数则用配置中的释放条件,默认不缓存关闭的界面
if (release === undefined) {
release = uip.config.destroy !== undefined ? uip.config.destroy : true;
}
release = state.config.destroy !== undefined ? state.config.destroy : true;
// 不释放界面,缓存起来待下次使用
if (release === false) {
this.ui_cache.set(uip.config.prefab, uip);
this.ui_cache.set(state.config.prefab, state);
}
const node = uip.node;
const node = state.node;
const comp = node.getComponent(LayerUIElement)!;
comp.remove(release);
}
// 验证是否删除后台缓存界面
if (release === true) this.removeCache(prefabPath);
// 清理界面缓存
const cache = this.ui_cache.get(prefabPath);
if (cache) {
// 验证是否删除后台缓存界面
if (release) this.removeCache(prefabPath);
}
}
/** 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面 */
private removeCache(prefabPath: string) {
let vp = this.ui_cache.get(prefabPath);
if (vp) {
this.onCloseWindow(vp);
this.uiClose(vp);
this.ui_cache.delete(prefabPath);
const node = vp.node;
const comp = node.getComponent(LayerUIElement)!;
@@ -177,6 +186,12 @@ export class LayerUI extends Node {
}
}
/** 显示界面 */
show(prefabPath: string) {
const vp = this.ui_nodes.get(prefabPath);
if (vp) vp.node.parent = this;
}
/**
* 根据预制路径获取已打开界面的节点对象
* @param prefabPath 预制路径
@@ -204,13 +219,13 @@ export class LayerUI extends Node {
const length = this.ui_nodes.array.length - 1;
for (let i = length; i >= 0; i--) {
const uip = this.ui_nodes.array[i];
this.remove(uip.config.prefab, isDestroy);
this.remove(uip.config.prefab);
}
this.ui_nodes.clear();
// 清除缓存中的界面
if (isDestroy) {
this.ui_cache.forEach((value: UIParams, prefabPath: string) => {
this.ui_cache.forEach((value: UIState, prefabPath: string) => {
this.removeCache(prefabPath);
});
}

View File

@@ -18,11 +18,9 @@ const { ccclass } = _decorator;
@ccclass('LayerUIElement')
export class LayerUIElement extends Component {
/** 视图参数 */
params: UIParams = null!;
state: UIState = null!;
/** 关闭窗口之前 */
onCloseWindowBefore: Function = null!;
/** 界面关闭回调 - 包括关闭动画播放完(辅助框架内存业务流程使用) */
private onCloseWindow: Function = null!;
onClose: Function = null!;
/** 添加界面且界面设置到父节点之前 */
add(): Promise<boolean> {
@@ -32,7 +30,7 @@ export class LayerUIElement extends Component {
const component: any = this.node.components[i];
const func = component[EventOnAdded];
if (func) {
if (await func.call(component, this.params.params) == false) {
if (await func.call(component, this.state.params.data) == false) {
resolve(false);
return;
}
@@ -40,8 +38,8 @@ export class LayerUIElement extends Component {
}
// 触发外部窗口显示前的事件(辅助实现自定义动画逻辑)
if (typeof this.params.callbacks.onAdded === "function") {
this.params.callbacks.onAdded(this.node, this.params.params);
if (typeof this.state.params.onAdded === "function") {
this.state.params.onAdded(this.node, this.state.params.data);
}
resolve(true);
@@ -49,14 +47,14 @@ export class LayerUIElement extends Component {
}
/** 删除节点该方法只能调用一次将会触发onBeforeRemoved回调 */
remove(isDestroy?: boolean) {
if (this.params.valid) {
remove(isDestroy: boolean) {
if (this.state.valid) {
// 触发窗口移除舞台之前事件
this.applyComponentsFunction(this.node, EventOnBeforeRemove, this.params.params);
this.applyComponentsFunction(this.node, EventOnBeforeRemove, this.state.params.data);
// 通知外部对象窗口组件上移除之前的事件(关闭窗口前的关闭动画处理)
if (typeof this.params.callbacks.onBeforeRemove === "function") {
this.params.callbacks.onBeforeRemove(this.node, this.onBeforeRemoveNext.bind(this, isDestroy));
if (typeof this.state.params.onBeforeRemove === "function") {
this.state.params.onBeforeRemove(this.node, this.onBeforeRemoveNext.bind(this, isDestroy));
}
else {
this.onBeforeRemoveNext(isDestroy);
@@ -68,28 +66,26 @@ export class LayerUIElement extends Component {
}
/** 窗口关闭前动画处理完后的回调方法,主要用于释放资源 */
private onBeforeRemoveNext(isDestroy?: boolean) {
this.onCloseWindowBefore && this.onCloseWindowBefore();
this.removed(this.params, isDestroy);
}
private onBeforeRemoveNext(isDestroy: boolean) {
this.state.valid = false;
/** 窗口组件中触发移除事件与释放窗口对象 */
private removed(uip: UIParams, isDestroy?: boolean) {
uip.valid = false;
if (uip.callbacks && typeof uip.callbacks.onRemoved === "function") {
uip.callbacks.onRemoved(this.node, uip.params);
if (this.state.params && typeof this.state.params.onRemoved === "function") {
this.state.params.onRemoved(this.node, this.state.params.data);
}
// 界面移除舞台事件
this.onCloseWindow && this.onCloseWindow(uip);
// 关闭动画播放完后,界面移除舞台
//@ts-ignore
this.node.parent.uiClose(this.state);
// 关闭动画播放完后,界面移除舞台事件
this.onClose && this.onClose();
if (isDestroy) {
// 释放界面显示对象
this.node.destroy();
// 释放界面相关资源
oops.res.release(uip.config.prefab, uip.config.bundle);
oops.res.release(this.state.config.prefab, this.state.config.bundle);
// oops.log.logView(`【界面管理】释放【${uip.config.prefab}】界面资源`);
}
@@ -98,7 +94,7 @@ export class LayerUIElement extends Component {
}
// 触发窗口组件上窗口移除之后的事件
this.applyComponentsFunction(this.node, EventOnRemoved, this.params.params);
this.applyComponentsFunction(this.node, EventOnRemoved, this.state.params.data);
}
private applyComponentsFunction(node: Node, funName: string, params: any) {
@@ -112,38 +108,33 @@ export class LayerUIElement extends Component {
}
onDestroy() {
this.params = null!;
this.onCloseWindowBefore = null!;
this.onCloseWindow = null!;
this.state = null!;
this.onClose = null!;
}
}
/** 本类型仅供gui模块内部使用请勿在功能逻辑中使用 */
export class UIParams {
export class UIState {
/** 界面唯一编号 */
uiid: string = null!;
/** 界面配置 */
config: UIConfig = null!;
/** 传递给打开界面的参数 */
params: any = null!;
/** 窗口事件 */
callbacks: UICallbacks = null!;
params: UIParam = null!;
/** 是否在使用状态 */
valid: boolean = true;
/** 界面根节点 */
node: Node = null!;
}
/** 界面关闭参数 */
export interface UIRemove {
/** 关闭是否释放资源内存 */
isDestroy?: boolean;
/** 界面动画播放完关闭事件 */
onRemoved?: Function;
}
/*** 界面打开参数 */
export interface UIParam {
/** 自定义传递参数 */
data?: any;
/** 是否开启预加载(默认不开启 - 开启后加载完不显示界面) */
preload?: boolean;
/*** 界面回调参数对象定义 */
export interface UICallbacks {
/**
* 节点添加到层级以后的回调
* @param node 当前界面节点
@@ -151,13 +142,6 @@ export interface UICallbacks {
*/
onAdded?: (node: Node, params: any) => void,
/**
* 窗口节点 destroy 之后回调
* @param node 当前界面节点
* @param params 外部传递参数
*/
onRemoved?: (node: Node | null, params: any) => void,
/**
* 如果指定onBeforeRemoved则next必须调用否则节点不会被正常删除。
*
@@ -167,6 +151,10 @@ export interface UICallbacks {
*/
onBeforeRemove?: (node: Node, next: Function) => void,
/** 网络异常时,窗口加载失败回调 */
onLoadFailure?: () => void;
/**
* 窗口节点 destroy 之后回调
* @param node 当前界面节点
* @param params 外部传递参数
*/
onRemoved?: (node: Node, params: any) => void
}

View File

@@ -39,7 +39,7 @@ export interface UIConfig {
vacancy?: boolean,
/** 是否打开窗口后显示背景遮罩(默认关闭) */
mask?: boolean;
/** 是否启动真机安全区域显示 */
/** 是否启动真机安全区域显示(默认关闭) */
safeArea?: boolean;
/** 界面弹出时的节点排序索引 */
siblingIndex?: number;

View File

@@ -5,7 +5,6 @@
* @LastEditTime: 2022-09-06 17:20:51
*/
import { UIRemove } from '../../core/gui/layer/LayerUIElement';
import { ecs } from '../../libs/ecs/ECS';
import { ECSModel } from '../../libs/ecs/ECSModel';
import { GameComponent } from './GameComponent';
@@ -43,13 +42,13 @@ export abstract class CCComp extends GameComponent implements ecs.IComp {
tid: number = -1;
/** 从父节点移除自己 */
remove(params?: UIRemove) {
remove() {
const cct = ECSModel.compCtors[this.tid];
if (this.ent) {
ModuleUtil.removeGui(this.ent, cct, params);
ModuleUtil.removeGui(this.ent, cct);
}
else {
console.error(`组件 ${this.name} 移除失败,实体不存在`);
console.error(`组件 ${this.name} 移除失败,组件未注册`);
}
}

View File

@@ -5,7 +5,6 @@
* @LastEditTime: 2022-09-06 17:22:05
*/
import { UIRemove } from '../../core/gui/layer/LayerUIElement';
import { ecs } from '../../libs/ecs/ECS';
import { ECSModel } from '../../libs/ecs/ECSModel';
import VMParent from '../../libs/model-view/VMParent';
@@ -55,13 +54,13 @@ export abstract class CCVMParentComp extends VMParent implements ecs.IComp {
tid: number = -1;
/** 从父节点移除自己 */
remove(params?: UIRemove) {
remove() {
const cct = ECSModel.compCtors[this.tid];
if (this.ent) {
ModuleUtil.removeGui(this.ent, cct, params);
ModuleUtil.removeGui(this.ent, cct);
}
else {
console.error(`组件 ${this.name} 移除失败,实体不存在`);
console.error(`组件 ${this.name} 移除失败,组件未注册`);
}
}

View File

@@ -11,7 +11,7 @@ import { IAudioParams } from "../../core/common/audio/IAudio";
import { EventDispatcher } from "../../core/common/event/EventDispatcher";
import { EventMessage, ListenerFunc } from "../../core/common/event/EventMessage";
import { AssetType, CompleteCallback, Paths, ProgressCallback, resLoader } from "../../core/common/loader/ResLoader";
import { LayerUIElement, UIRemove } from "../../core/gui/layer/LayerUIElement";
import { LayerUIElement } from "../../core/gui/layer/LayerUIElement";
import { ViewUtil } from "../../core/utils/ViewUtil";
const { ccclass } = _decorator;
@@ -483,18 +483,10 @@ export class GameComponent extends Component {
//#endregion
/** 移除自己 */
remove(params?: UIRemove) {
if (params == null) {
params = { isDestroy: true };
}
else {
if (params.isDestroy == null) params.isDestroy = true;
}
remove() {
const comp = this.node.getComponent(LayerUIElement);
if (comp) {
if (params.onRemoved) comp.onCloseWindowBefore = params.onRemoved;
oops.gui.removeByNode(this.node, params.isDestroy);
oops.gui.removeByNode(this.node);
}
}

View File

@@ -2,8 +2,7 @@ import { Node, __private } from "cc";
import { oops } from "../../core/Oops";
import { resLoader } from "../../core/common/loader/ResLoader";
import { gui } from "../../core/gui/Gui";
import { Uiid } from "../../core/gui/layer/LayerEnum";
import { LayerUIElement, UICallbacks, UIRemove } from "../../core/gui/layer/LayerUIElement";
import { LayerUIElement, UIParam } from "../../core/gui/layer/LayerUIElement";
import { ViewUtil } from "../../core/utils/ViewUtil";
import { ecs } from "../../libs/ecs/ECS";
import { CompType } from "../../libs/ecs/ECSModel";
@@ -17,29 +16,26 @@ export class ModuleUtil {
* 异步添加视图层组件
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param uiArgs 界面参数
* @param anim 界面打开与关闭动画
* @param params 界面参数
* @returns 界面节点
*/
static addGui<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, uiArgs?: any, anim?: UICallbacks): Promise<Node | null> {
return new Promise<Node | null>((resolve, reject) => {
const uic: UICallbacks = {
onAdded: (node: Node, params: any) => {
const comp = node.getComponent(ctor) as ecs.Comp;
ent.add(comp);
if (anim && anim.onAdded) anim.onAdded(node, params);
resolve(node);
},
onLoadFailure: () => {
if (anim && anim.onLoadFailure) anim.onLoadFailure();
resolve(null);
}
};
static addGui<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, params?: UIParam): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
//@ts-ignore
const key = ctor[gui.internal.GUI_KEY];
if (key) {
oops.gui.open(key, uiArgs, uic);
if (params == null) {
params = { preload: true };
}
else {
params.preload = true;
}
let node = await oops.gui.open(key, params);
const comp = node.getComponent(ctor) as ecs.Comp;
ent.add(comp);
oops.gui.show(key);
resolve(node);
}
else {
console.error(`${key} 界面组件未使用 gui.register 注册`);
@@ -49,18 +45,11 @@ export class ModuleUtil {
/**
* 业务实体上移除界面组件
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param params 界面关闭参数
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param params 界面关闭参数
*/
static removeGui(ent: ecs.Entity, ctor: CompType<ecs.IComp>, params?: UIRemove) {
if (params == null) {
params = { isDestroy: true };
}
else {
if (params.isDestroy == null) params.isDestroy = true;
}
static removeGui(ent: ecs.Entity, ctor: CompType<ecs.IComp>) {
//@ts-ignore
const key = ctor[gui.internal.GUI_KEY];
if (key) {
@@ -72,16 +61,14 @@ export class ModuleUtil {
const comp = node.getComponent(LayerUIElement);
if (comp) {
comp.onCloseWindowBefore = () => {
if (params.isDestroy) ent.remove(ctor);
if (params.onRemoved) params.onRemoved();
comp.onClose = () => {
if (comp.state.config.destroy) ent.remove(ctor);
};
oops.gui.remove(key, params.isDestroy);
oops.gui.remove(key);
}
}
else {
if (params.isDestroy) ent.remove(ctor);
if (params.onRemoved) params.onRemoved();
ent.remove(ctor);
}
}
@@ -99,77 +86,4 @@ export class ModuleUtil {
ent.add(comp);
node.parent = parent;
}
//#region deprecated
/**
* 添加界面组件
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param uiId 界面资源编号
* @param uiArgs 界面参数
* @deprecated 使用gui.register注册的界面组件可使用add方法打开
*/
static addViewUi<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, uiId: Uiid, uiArgs: any = null) {
const uic: UICallbacks = {
onAdded: (node: Node, params: any) => {
const comp = node.getComponent(ctor) as ecs.Comp;
//@ts-ignore
if (!ent.has(ctor)) ent.add(comp);
}
};
oops.gui.open(uiId, uiArgs, uic);
}
/**
* 异步添加视图层组件
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param uiId 界面资源编号
* @param uiArgs 界面参数
* @returns 界面节点
* @deprecated 使用gui.register注册的界面组件可使用add方法打开
*/
static addViewUiAsync<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, uiId: Uiid, uiArgs: any = null): Promise<Node | null> {
return new Promise<Node | null>((resolve, reject) => {
const uic: UICallbacks = {
onAdded: (node: Node, params: any) => {
const comp = node.getComponent(ctor) as ecs.Comp;
ent.add(comp);
resolve(node);
},
onLoadFailure: () => {
resolve(null);
}
};
oops.gui.open(uiId, uiArgs, uic);
});
}
/**
* 业务实体上移除界面组件
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param uiId 界面资源编号
* @param isDestroy 是否释放界面缓存(默认为释放界面缓存)
* @param onRemoved 窗口关闭完成事件
* @deprecated 使用gui.register注册的界面组件可使用remove方法移除
*/
static removeViewUi(ent: ecs.Entity, ctor: CompType<ecs.IComp>, uiId: Uiid, isDestroy: boolean = true, onRemoved?: Function) {
const node = oops.gui.get(uiId);
if (!node) {
if (onRemoved) onRemoved();
return;
}
const comp = node.getComponent(LayerUIElement);
if (comp) {
comp.onCloseWindowBefore = () => {
// 移除ECS显示组件
if (isDestroy) ent.remove(ctor, isDestroy);
if (onRemoved) onRemoved();
};
oops.gui.remove(uiId, isDestroy);
}
}
//#endregion
}