1. 支持GUI模块直接通过配置参数打开界面

2. 修复后台缓存模式下,界面资源内存泄露
3. 整理界面管理模块的代码
This commit is contained in:
dgflash
2025-04-04 23:17:59 +08:00
parent f1702f91a5
commit 195aa416b3
10 changed files with 186 additions and 119 deletions

View File

@@ -5,7 +5,7 @@
* @LastEditTime: 2023-01-09 11:52:38
*/
import { Node } from "cc";
import { UIConfig } from "./LayerManager";
import { UIConfig } from "./UIConfig";
/*** 界面回调参数对象定义 */
export interface UICallbacks {
@@ -38,6 +38,8 @@ export interface UICallbacks {
/** 本类型仅供gui模块内部使用请勿在功能逻辑中使用 */
export class ViewParams {
/** 界面唯一编号 */
uiid: number = -1;
/** 界面配置 */
config: UIConfig = null!;
/** 传递给打开界面的参数 */

View File

@@ -62,6 +62,9 @@ export class DelegateComponent extends Component {
this.removed(this.vp, isDestroy);
}
}
else {
this.removed(this.vp, isDestroy);
}
}
/** 窗口关闭前动画处理完后的回调方法,主要用于释放资源 */
@@ -87,7 +90,12 @@ export class DelegateComponent extends Component {
// 释放界面相关资源
oops.res.release(vp.config.prefab, vp.config.bundle);
// oops.log.logView(`【界面管理】释放【${vp.config.prefab}】界面资源`);
// 释放自动递增编号的界面配置
if (vp.config.auto) {
oops.gui.setConfig(vp.uiid, null!);
}
oops.log.logView(`【界面管理】释放【${vp.config.prefab}】界面资源`);
}
else {
this.node.removeFromParent();

View File

@@ -6,8 +6,8 @@
*/
import { UICallbacks, ViewParams } from "./Defines";
import { UIConfig } from "./LayerManager";
import { LayerPopUp } from "./LayerPopup";
import { UIConfig } from "./UIConfig";
/** 模式弹窗数据 */
type DialogParam = {
@@ -23,7 +23,7 @@ export class LayerDialog extends LayerPopUp {
/** 窗口调用参数队列 */
private params: Array<DialogParam> = [];
add(config: UIConfig, params?: any, callbacks?: UICallbacks) {
add(uiid: number, config: UIConfig, params?: any, callbacks?: UICallbacks) {
// 控制同一时间只能显示一个模式窗口
if (this.ui_nodes.size > 0) {
this.params.push({

View File

@@ -0,0 +1,41 @@
/** 屏幕适配类型 */
export enum ScreenAdapterType {
/** 自动适配 */
Auto,
/** 横屏适配 */
Landscape,
/** 竖屏适配 */
Portrait
}
/** 界面层类型 */
export enum LayerType {
/** 二维游戏层 */
Game = "LayerGame",
/** 主界面层 */
UI = "LayerUI",
/** 弹窗层 */
PopUp = "LayerPopUp",
/** 模式窗口层 */
Dialog = "LayerDialog",
/** 系统触发模式窗口层 */
System = "LayerSystem",
/** 消息提示层 */
Notify = "LayerNotify",
/** 新手引导层 */
Guide = "LayerGuide"
}
/** 界面层组件类型 */
export enum LayerTypeCls {
/** 主界面层 */
UI = "UI",
/** 弹窗层 */
PopUp = "PopUp",
/** 模式窗口层 */
Dialog = "Dialog",
/** 消息提示层 */
Notify = "Notify",
/** 自定义节点层 */
Node = "Node"
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "a33b5645-72a0-4590-80c9-b0ff4a33fe9c",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -3,90 +3,23 @@ import { oops } from "../../Oops";
import { UICallbacks } from "./Defines";
import { DelegateComponent } from "./DelegateComponent";
import { LayerDialog } from "./LayerDialog";
import { LayerType, LayerTypeCls } from "./LayerEnum";
import { LayerNotify } from "./LayerNotify";
import { LayerPopUp } from "./LayerPopup";
import { LayerUI } from "./LayerUI";
import { UIConfig } from "./UIConfig";
/** 屏幕适配类型 */
export enum ScreenAdapterType {
/** 自动适配 */
Auto,
/** 横屏适配 */
Landscape,
/** 竖屏适配 */
Portrait
}
/** 自动生成界面编号最小值 */
const uiidMin = 1000000;
/** 自动生成界面编号最大值 */
const uiidMax = 9999999;
var uiid: number = uiidMin; // 当前自动递增界面编号
/** 界面层类型 */
export enum LayerType {
/** 二维游戏层 */
Game = "LayerGame",
/** 主界面层 */
UI = "LayerUI",
/** 弹窗层 */
PopUp = "LayerPopUp",
/** 模式窗口层 */
Dialog = "LayerDialog",
/** 系统触发模式窗口层 */
System = "LayerSystem",
/** 消息提示层 */
Notify = "LayerNotify",
/** 新手引导层 */
Guide = "LayerGuide"
}
/** 界面层组件类型 */
export enum LayerTypeCls {
/** 主界面层 */
UI = "UI",
/** 弹窗层 */
PopUp = "PopUp",
/** 模式窗口层 */
Dialog = "Dialog",
/** 消息提示层 */
Notify = "Notify",
/** 自定义节点层 */
Node = "Node"
}
/**
* 界面配置结构体
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037986&doc_id=2873565
* @example
// 界面唯一标识
export enum UIID {
Loading = 1,
Window,
Netinstable
}
// 打开界面方式的配置数据
export var UIConfigData: { [key: number]: UIConfig } = {
[UIID.Loading]: { layer: LayerType.UI, prefab: "loading/prefab/loading", bundle: "resources" },
[UIID.Netinstable]: { layer: LayerType.PopUp, prefab: "common/prefab/netinstable" },
[UIID.Window]: { layer: LayerType.Dialog, prefab: "common/prefab/window" }
}
*/
export interface UIConfig {
/** -----公共属性----- */
/** 远程包名 */
bundle?: string;
/** 窗口层级 */
layer: string;
/** 预制资源相对路径 */
prefab: string;
/** 是否自动施放(默认不自动释放) */
destroy?: boolean;
/** -----弹窗属性----- */
/** 是否触摸非窗口区域关闭(默认关闭) */
vacancy?: boolean,
/** 是否打开窗口后显示背景遮罩(默认关闭) */
mask?: boolean;
/** 是否启动真机安全区域显示 */
safeArea?: boolean;
/** 界面弹出时的节点排序索引 */
siblingIndex?: number;
/** 自动获取界面唯一编号 */
function getUiid(): number {
if (uiid == uiidMax) uiid = uiidMin;
uiid++;
return uiid;
}
/** 界面层级管理器 */
@@ -253,16 +186,19 @@ export class LayerManager {
/**
* 设置界面配置
* @param uiId 要设置的界面id
* @param uiid 要设置的界面id
* @param config 要设置的配置
*/
setConfig(uiId: number, config: UIConfig): void {
this.configs[uiId] = config;
setConfig(uiid: number, config: UIConfig): void {
if (config)
this.configs[uiid] = config;
else
delete this.configs[uiid];
}
/**
* 同步打开一个窗口
* @param uiId 窗口唯一编号
* @param uiid 窗口唯一编号
* @param uiArgs 窗口参数
* @param callbacks 回调对象
* @example
@@ -276,30 +212,30 @@ export class LayerManager {
};
oops.gui.open(UIID.Loading, null, uic);
*/
open(uiId: number, uiArgs: any = null, callbacks?: UICallbacks): void {
const config = this.configs[uiId];
open(uiid: number, uiArgs: any = null, callbacks?: UICallbacks): void {
const config = this.configs[uiid];
if (config == null) {
warn(`打开编号为【${uiId}】的界面失败,配置信息不存在`);
warn(`打开编号为【${uiid}】的界面失败,配置信息不存在`);
return;
}
let layer = this.uiLayers.get(config.layer);
if (layer) {
layer.add(config, uiArgs, callbacks);
layer.add(uiid, config, uiArgs, callbacks);
}
else {
console.error(`打开编号为【${uiId}】的界面失败,界面层不存在`);
console.error(`打开编号为【${uiid}】的界面失败,界面层不存在`);
}
}
/**
* 异步打开一个窗口
* @param uiId 窗口唯一编号
* @param uiid 窗口唯一编号
* @param uiArgs 窗口参数
* @example
* var node = await oops.gui.openAsync(UIID.Loading);
*/
async openAsync(uiId: number, uiArgs: any = null): Promise<Node | null> {
async openAsync(uiid: number, uiArgs: any = null): Promise<Node | null> {
return new Promise<Node | null>((resolve, reject) => {
const callbacks: UICallbacks = {
onAdded: (node: Node, params: any) => {
@@ -309,7 +245,22 @@ export class LayerManager {
resolve(null);
}
};
this.open(uiId, uiArgs, callbacks);
this.open(uiid, uiArgs, callbacks);
});
}
/**
* 通过界面配置打开一个界面
* @param config 界面配置数据
* @returns
*/
openAsyncConfig(config: UIConfig): Promise<number> {
return new Promise(async (resolve, reject) => {
let uiid = getUiid();
config.auto = true;
this.setConfig(uiid, config);
await oops.gui.openAsync(uiid, { uiid: uiid });
resolve(uiid);
});
}
@@ -350,14 +301,14 @@ export class LayerManager {
/**
* 缓存中是否存在指定标识的窗口
* @param uiId 窗口唯一标识
* @param uiid 窗口唯一标识
* @example
* oops.gui.has(UIID.Loading);
*/
has(uiId: number): boolean {
const config = this.configs[uiId];
has(uiid: number): boolean {
const config = this.configs[uiid];
if (config == null) {
warn(`编号为【${uiId}】的界面配置不存在,配置信息不存在`);
warn(`编号为【${uiid}】的界面配置不存在,配置信息不存在`);
return false;
}
@@ -367,7 +318,7 @@ export class LayerManager {
result = layer.has(config.prefab);
}
else {
console.error(`验证编号为【${uiId}】的界面失败,界面层不存在`);
console.error(`验证编号为【${uiid}】的界面失败,界面层不存在`);
}
return result;
@@ -375,14 +326,14 @@ export class LayerManager {
/**
* 缓存中是否存在指定标识的窗口
* @param uiId 窗口唯一标识
* @param uiid 窗口唯一标识
* @example
* oops.gui.has(UIID.Loading);
*/
get(uiId: number): Node {
const config = this.configs[uiId];
get(uiid: number): Node {
const config = this.configs[uiid];
if (config == null) {
warn(`编号为【${uiId}】的界面配置不存在,配置信息不存在`);
warn(`编号为【${uiid}】的界面配置不存在,配置信息不存在`);
return null!;
}
@@ -392,22 +343,22 @@ export class LayerManager {
result = layer.get(config.prefab);
}
else {
console.error(`获取编号为【${uiId}】的界面失败,界面层不存在`);
console.error(`获取编号为【${uiid}】的界面失败,界面层不存在`);
}
return result;
}
/**
* 移除指定标识的窗口
* @param uiId 窗口唯一标识
* @param isDestroy 移除后是否释放
* @param uiid 窗口唯一标识
* @param isDestroy 移除后是否释放(默认释放内存)
* @example
* oops.gui.remove(UIID.Loading);
*/
remove(uiId: number, isDestroy?: boolean) {
const config = this.configs[uiId];
remove(uiid: number, isDestroy: boolean = true) {
const config = this.configs[uiid];
if (config == null) {
warn(`删除编号为【${uiId}】的界面失败,配置信息不存在`);
warn(`删除编号为【${uiid}】的界面失败,配置信息不存在`);
return;
}
@@ -416,24 +367,24 @@ export class LayerManager {
layer.remove(config.prefab, isDestroy);
}
else {
console.error(`移除编号为【${uiId}】的界面失败,界面层不存在`);
console.error(`移除编号为【${uiid}】的界面失败,界面层不存在`);
}
}
/**
* 删除一个通过this框架添加进来的节点
* 通过界面节点移除
* @param node 窗口节点
* @param isDestroy 移除后是否释放资源
* @param isDestroy 移除后是否释放资源(默认释放内存)
* @example
* oops.gui.removeByNode(cc.Node);
*/
removeByNode(node: Node, isDestroy?: boolean) {
removeByNode(node: Node, isDestroy: boolean = true) {
if (node instanceof Node) {
let comp = node.getComponent(DelegateComponent);
if (comp && comp.vp) {
// 释放显示的界面
if (node.parent) {
this.uiLayers.get(comp.vp.config.layer)!.remove(comp.vp.config.prefab, isDestroy);
this.remove(comp.vp.uiid, isDestroy);
}
// 释放缓存中的界面
else if (isDestroy) {
@@ -445,7 +396,7 @@ export class LayerManager {
}
}
else {
warn(`当前删除的node不是通过界面管理器添加到舞台上`);
warn(`当前删除的 Node 不是通过界面管理器添加`);
node.destroy();
}
}

View File

@@ -8,8 +8,8 @@ import { BlockInputEvents, EventTouch, Layers, Node } from "cc";
import { ViewUtil } from "../../utils/ViewUtil";
import { PromptResType } from "../GuiEnum";
import { ViewParams } from "./Defines";
import { UIConfig } from "./LayerManager";
import { LayerUI } from "./LayerUI";
import { UIConfig } from "./UIConfig";
/* 弹窗层,允许同时弹出多个窗口 */
export class LayerPopUp extends LayerUI {

View File

@@ -3,7 +3,7 @@ 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";
import { UIConfig } from "./UIConfig";
/** 界面层对象 */
export class LayerUI extends Node {
@@ -35,7 +35,7 @@ export class LayerUI extends Node {
* @param callbacks 回调函数对象,可选
* @returns ture为成功,false为失败
*/
add(config: UIConfig, params?: any, callbacks?: UICallbacks) {
add(uiid: number, config: UIConfig, params?: any, callbacks?: UICallbacks) {
if (this.ui_nodes.has(config.prefab)) {
console.warn(`路径为【${config.prefab}】的预制重复加载`);
return;
@@ -45,6 +45,7 @@ export class LayerUI extends Node {
let vp = this.ui_cache.get(config.prefab);
if (vp == null) {
vp = new ViewParams();
vp.uiid = uiid;
vp.config = config;
}
this.ui_nodes.set(config.prefab, vp);
@@ -172,6 +173,10 @@ export class LayerUI extends Node {
this.onCloseWindow(vp);
this.ui_cache.delete(prefabPath);
const childNode = vp.node;
const comp = childNode.getComponent(DelegateComponent)!;
if (comp) {
comp.remove(true);
}
childNode.destroy();
}
}

View File

@@ -0,0 +1,42 @@
/**
* 界面配置结构体
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037986&doc_id=2873565
* @example
// 界面唯一标识
export enum UIID {
Loading = 1,
Window,
Netinstable
}
// 打开界面方式的配置数据
export var UIConfigData: { [key: number]: UIConfig } = {
[UIID.Loading]: { layer: LayerType.UI, prefab: "loading/prefab/loading", bundle: "resources" },
[UIID.Netinstable]: { layer: LayerType.PopUp, prefab: "common/prefab/netinstable" },
[UIID.Window]: { layer: LayerType.Dialog, prefab: "common/prefab/window" }
}
*/
export interface UIConfig {
/** 是否为自动生成的界面编号 */
auto?: boolean,
/** -----公共属性----- */
/** 远程包名 */
bundle?: string;
/** 窗口层级 */
layer: string;
/** 预制资源相对路径 */
prefab: string;
/** 是否自动施放(默认不自动释放) */
destroy?: boolean;
/** -----弹窗属性----- */
/** 是否触摸非窗口区域关闭(默认关闭) */
vacancy?: boolean,
/** 是否打开窗口后显示背景遮罩(默认关闭) */
mask?: boolean;
/** 是否启动真机安全区域显示 */
safeArea?: boolean;
/** 界面弹出时的节点排序索引 */
siblingIndex?: number;
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "41bb526c-a934-4564-9c6e-e2f6a7ba6114",
"files": [],
"subMetas": {},
"userData": {}
}