优化Gui模块

This commit is contained in:
dgflash
2025-09-12 09:25:24 +08:00
parent 0a9112ea64
commit 1feb30628f
7 changed files with 108 additions and 79 deletions

View File

@@ -17,6 +17,12 @@ export namespace gui {
export namespace internal {
/** 界面唯一标记变量名 */
export const GUI_KEY = "OOPS_GUI_KEY";
/** 获取界面唯一关键字 */
export function getKey(ctor: any) {
return ctor[GUI_KEY];
}
/** 获取界面组件配置 */
export function getConfig(key: string) {
return configs[key];

View File

@@ -1,5 +1,4 @@
import { Camera, Node, ResolutionPolicy, SafeArea, screen, view, warn } from "cc";
import { resLoader } from "../../common/loader/ResLoader";
import { oops } from "../../Oops";
import { gui } from "../Gui";
import { LayerDialog } from "./LayerDialog";
@@ -260,6 +259,23 @@ export class LayerManager {
}
}
/**
* 清理指定界面的缓存
* @param uiid 窗口唯一标识
* @example
* oops.gui.removeCache(UIID.Loading);
*/
removeCache(uiid: Uiid) {
let info = this.getInfo(uiid);
let layer = this.uiLayers.get(info.config.layer);
if (layer) {
layer.removeCache(info.config.prefab);
}
else {
console.error(`移除编号为【${uiid}】的界面失败,界面层不存在`);
}
}
/**
* 通过界面节点移除
* @param node 窗口节点

View File

@@ -17,19 +17,13 @@ export class LayerPopUp extends LayerUI {
/** 半透明遮罩资源 */
protected mask!: Node;
constructor(name: string) {
super(name);
this.on(Node.EventType.CHILD_ADDED, this.onChildAdded, this);
this.on(Node.EventType.CHILD_REMOVED, this.onChildRemoved, this);
}
private onChildAdded(child: Node) {
protected onChildAdded(child: Node) {
this.mask.setSiblingIndex(this.children.length - 2);
}
private onChildRemoved(child: Node) {
protected onChildRemoved(child: Node) {
this.mask.setSiblingIndex(this.children.length - 2);
super.onChildRemoved(child);
}
protected uiInit(state: UIState): Promise<boolean> {

View File

@@ -23,6 +23,20 @@ export class LayerUI extends Node {
constructor(name: string) {
super(name);
LayerHelper.setFullScreen(this);
this.on(Node.EventType.CHILD_ADDED, this.onChildAdded, this);
this.on(Node.EventType.CHILD_REMOVED, this.onChildRemoved, this);
}
protected onChildAdded(child: Node) {
}
protected onChildRemoved(child: Node) {
const comp = child.getComponent(LayerUIElement);
if (comp) {
this.closeUi(comp.state);
}
}
/**
@@ -74,8 +88,9 @@ export class LayerUI extends Node {
protected async load(state: UIState): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
// 加载界面资源超时提示
let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
if (state.node == null) {
let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui);
// 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源
const res = await resLoader.loadAsync(state.config.bundle!, state.config.prefab, Prefab);
if (res) {
@@ -92,14 +107,13 @@ export class LayerUI extends Node {
console.warn(`路径为【${state.config.prefab}】的预制加载失败`);
this.failure(state);
}
// 关闭界面资源超时提示
oops.gui.waitClose();
clearTimeout(timerId);
}
// 关闭界面资源超时提示
oops.gui.waitClose();
clearTimeout(timerId);
await this.uiInit(state);
resolve(state.node);
});
}
@@ -157,40 +171,30 @@ export class LayerUI extends Node {
release = state.config.destroy !== undefined ? state.config.destroy : true;
// 不释放界面,缓存起来待下次使用
if (release === false) {
this.ui_cache.set(state.config.prefab, state);
}
if (release === false) this.ui_cache.set(state.config.prefab, state);
const node = state.node;
const comp = node.getComponent(LayerUIElement)!;
const comp = state.node.getComponent(LayerUIElement)!;
comp.remove(release);
}
// 清理界面缓存
const cache = this.ui_cache.get(prefabPath);
if (cache) {
// 验证是否删除后台缓存界面
if (release) this.removeCache(prefabPath);
}
// 验证是否删除后台缓存界面
if (release) this.removeCache(prefabPath);
}
/** 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面 */
private removeCache(prefabPath: string) {
let vp = this.ui_cache.get(prefabPath);
if (vp) {
this.closeUi(vp);
removeCache(prefabPath: string) {
const state = this.ui_cache.get(prefabPath);
if (state) {
this.ui_cache.delete(prefabPath);
const node = vp.node;
const comp = node.getComponent(LayerUIElement)!;
const comp = state.node.getComponent(LayerUIElement)!;
comp.remove(true);
node.destroy();
}
}
/** 显示界面 */
show(prefabPath: string) {
const vp = this.ui_nodes.get(prefabPath);
if (vp) vp.node.parent = this;
const state = this.ui_nodes.get(prefabPath);
if (state) state.node.parent = this;
}
/**
@@ -198,8 +202,8 @@ export class LayerUI extends Node {
* @param prefabPath 预制路径
*/
get(prefabPath: string): Node {
const vp = this.ui_nodes.get(prefabPath);
if (vp) return vp.node;
const state = this.ui_nodes.get(prefabPath);
if (state) return state.node;
return null!;
}

View File

@@ -73,10 +73,6 @@ export class LayerUIElement extends Component {
this.state.params.onRemoved(this.node, this.state.params.data);
}
// 关闭动画播放完后,界面移除舞台
//@ts-ignore
this.node.parent.closeUi(this.state);
// 关闭动画播放完后,界面移除舞台事件
this.onClose && this.onClose();

View File

@@ -1,32 +1,32 @@
import { Label, _decorator } from "cc";
import { EDITOR } from "cc/env";
import { oops } from "../../../core/Oops";
import { EventMessage } from "../../../core/common/event/EventMessage";
import { TimeUtil } from "../../../core/utils/TimeUtils";
import { EDITOR } from "cc/env";
const { ccclass, property, menu } = _decorator;
/** 倒计时标签 */
@ccclass("LabelTime")
@menu('OopsFramework/Label/LabelTime (倒计时标签)')
@menu("OopsFramework/Label/LabelTime (倒计时标签)")
export default class LabelTime extends Label {
@property({
tooltip: "到计时间总时间(单位秒)"
tooltip: "到计时间总时间(单位秒)",
})
countDown: number = 1000;
@property({
tooltip: "天数数据格式化"
tooltip: "天数数据格式化",
})
dayFormat: string = "{0} day";
@property({
tooltip: "时间格式化"
tooltip: "时间格式化",
})
timeFormat: string = "{0}:{1}:{2}";
@property({
tooltip: "是否有00"
tooltip: "是否有00",
})
zeroize: boolean = true;
@@ -35,9 +35,9 @@ export default class LabelTime extends Label {
})
paused: boolean = false;
private backStartTime: number = 0; // 进入后台开始时间
private dateDisable!: boolean; // 时间能否由天数显示
private result!: string; // 时间结果字符串
private backStartTime: number = 0; // 进入后台开始时间
private dateDisable!: boolean; // 时间能否由天数显示
private result!: string; // 时间结果字符串
/** 每秒触发事件 */
onSecond: Function = null!;
@@ -45,10 +45,9 @@ export default class LabelTime extends Label {
onComplete: Function = null!;
private replace(value: string, ...args: any): string {
return value.replace(/\{(\d+)\}/g,
function (m, i) {
return args[i];
});
return value.replace(/\{(\d+)\}/g, function (m, i) {
return args[i];
});
}
/** 格式化字符串 */
@@ -84,23 +83,15 @@ export default class LabelTime extends Label {
if (date < 2) {
df = df.replace("days", "day");
}
this.result = this.replace(df, date, hours); // 如果天大于1则显示 "1 Day..."
this.result = this.replace(df, date, hours); // 如果天大于1则显示 "1 Day..."
}
else {
hours += date * 24;
if (this.zeroize) {
this.result = this.replace(
this.timeFormat,
this.coverString(hours),
this.coverString(minutes),
this.coverString(seconds)); // 否则显示 "01:12:24"
this.result = this.replace(this.timeFormat, this.coverString(hours), this.coverString(minutes), this.coverString(seconds)); // 否则显示 "01:12:24"
}
else {
this.result = this.replace(
this.timeFormat,
hours,
minutes,
seconds);
this.result = this.replace(this.timeFormat, hours, minutes, seconds);
}
}
this.string = this.result;
@@ -108,8 +99,7 @@ export default class LabelTime extends Label {
/** 个位数的时间数据将字符串补位 */
private coverString(value: number) {
if (value < 10)
return "0" + value;
if (value < 10) return "0" + value;
return value.toString();
}
@@ -123,7 +113,7 @@ export default class LabelTime extends Label {
* @param second 倒计时时间(单位秒)
*/
setTime(second: number) {
this.countDown = second; // 倒计时,初始化显示字符串
this.countDown = second; // 倒计时,初始化显示字符串
this.timing_end();
this.timing_start();
this.format();
@@ -140,15 +130,33 @@ export default class LabelTime extends Label {
this.format();
}
start() {
onLoad() {
if (!EDITOR) {
oops.message.on(EventMessage.GAME_SHOW, this.onGameShow, this);
oops.message.on(EventMessage.GAME_HIDE, this.onGameHide, this);
}
}
start() {
if (this.countDown <= 0) return;
this.timing_start();
this.format();
}
onEnable() {
super.onEnable();
if (!EDITOR) {
this.onGameShow();
}
}
onDisable() {
super.onDisable();
if (!EDITOR) {
this.onGameHide();
}
}
onDestroy() {
if (!EDITOR) {
oops.message.off(EventMessage.GAME_SHOW, this.onGameShow, this);
@@ -175,6 +183,12 @@ export default class LabelTime extends Label {
}
private onScheduleSecond() {
if (this.countDown == 0) {
this.format();
this.onScheduleComplete();
return;
}
this.countDown--;
this.format();
if (this.onSecond) this.onSecond(this.node);
@@ -187,15 +201,17 @@ export default class LabelTime extends Label {
private onScheduleComplete() {
this.timing_end();
this.format();
this.unschedule(this.onScheduleSecond);
if (this.onComplete) this.onComplete(this.node);
}
/** 开始计时 */
private timing_start() {
timing_start() {
this.schedule(this.onScheduleSecond, 1);
}
private timing_end() {
/** 关闭计时 */
timing_end() {
this.unscheduleAllCallbacks();
}
}

View File

@@ -35,8 +35,7 @@ export class CCEntity extends ecs.Entity {
*/
addUi<T extends CCVMParentComp | CCComp>(ctor: ECSCtor<T>, params?: UIParam): Promise<Node> {
return new Promise<Node>(async (resolve, reject) => {
//@ts-ignore
const key = ctor[gui.internal.GUI_KEY];
const key = gui.internal.getKey(ctor);
if (key) {
if (params == null) {
params = { preload: true };
@@ -62,8 +61,7 @@ export class CCEntity extends ecs.Entity {
* @param ctor 界面逻辑组件
*/
removeUi(ctor: CompType<ecs.IComp>) {
//@ts-ignore
const key = ctor[gui.internal.GUI_KEY];
const key = gui.internal.getKey(ctor);
if (key) {
const node = oops.gui.get(key);
if (node == null) {
@@ -73,9 +71,8 @@ export class CCEntity extends ecs.Entity {
const comp = node.getComponent(LayerUIElement);
if (comp) {
comp.onClose = () => {
if (comp.state.config.destroy) this.remove(ctor);
};
// 处理界面关闭动画播放完成后移除ECS组件避免使用到组件实体数据还在动画播放时在使用导致的空对象问题
comp.onClose = this.remove.bind(this, ctor);
oops.gui.remove(key);
}
}