Framework.UI简单UI管理类

This commit is contained in:
janing
2025-12-14 22:40:38 +08:00
parent 0a30c28316
commit b0938a9fb8
10 changed files with 1165 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "9fc0bab1-69b0-4f45-9f40-e4711ee0a541",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "6196366f-2afd-4ade-a6b3-7a675ed9a56f",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "f6e8a8b0-3c5d-4e7f-9d2a-8f5c6d4e7a9b",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,447 @@
# UI 系统 (Framework/UI)
## 📋 模块概述
统一的 UI 管理系统,管理 UI 的加载、显示、隐藏和生命周期,提供 UI 基类和管理器,支持缓存和自动资源管理。
## 🎯 核心特性
- ✅ UI 基类定义
- ✅ UI 生命周期管理
- ✅ UI 缓存机制
- ✅ 自动资源管理
- ✅ UI 更新机制
- ✅ 类型安全
## 🗂️ 文件结构
```
Framework/UI/
├── UIBase.ts # UI 基类
├── UIMgr.ts # UI 管理器
└── UIMgrExample.ts # 使用示例
```
## 📘 核心类详解
### UIBase - UI 基类
**职责**: 定义 UI 的基础接口和生命周期
```typescript
abstract class UIBase {
protected _node: Node | null; // UI 根节点
protected _isLoaded: boolean; // 是否已加载
protected _isShowing: boolean; // 是否显示中
// 必须重载: 获取 UI 资源路径
abstract onGetUrl(): string;
// 可选重载: UI 初始化(加载完成后)
onStart?(params?: any): void | Promise<void>;
// 可选重载: UI 清理(卸载前)
onEnd?(): void;
// 可选重载: 每帧更新
onUpdate?(dt: number): void;
// 设置 UI 根节点
setNode(node: Node): void;
// 获取 UI 根节点
getNode(): Node | null;
// 显示 UI
show(): void;
// 隐藏 UI
hide(): void;
// 检查是否显示中
isShowing(): boolean;
// 检查是否已加载
isLoaded(): boolean;
}
```
### UIMgr - UI 管理器
**职责**: 管理 UI 的加载、卸载和生命周期
```typescript
class UIMgr {
private _uiCache: Map<string, UIBase>; // UI 缓存
private _uiRoot: Node | null; // UI 根节点
private _updateList: UIBase[]; // 需要更新的 UI 列表
// 获取单例
static getInstance(): UIMgr;
// 设置 UI 根节点(Canvas)
setUIRoot(root: Node): void;
// 加载并显示 UI
async load<T extends UIBase>(
uiClass: new () => T,
params?: any
): Promise<T>;
// 卸载 UI
unload(uiClass: (new () => UIBase) | string): void;
// 获取已加载的 UI 实例
get<T extends UIBase>(uiClass: (new () => T) | string): T | null;
// 检查 UI 是否已加载
has(uiClass: (new () => UIBase) | string): boolean;
// 更新所有需要更新的 UI
update(dt: number): void;
// 卸载所有 UI
unloadAll(): void;
// 销毁管理器
destroy(): void;
}
```
## 📝 使用指南
### 1. 创建自定义 UI
```typescript
import { _decorator } from 'cc';
import { UIBase } from './Framework/UI/UIBase';
const { ccclass } = _decorator;
@ccclass('UILogin')
export class UILogin extends UIBase {
private _btnLogin: Node | null = null;
private _inputAccount: EditBox | null = null;
/**
* 必须重载: 返回 UI 资源路径
*/
onGetUrl(): string {
return 'prefabs/ui/UILogin';
}
/**
* 可选重载: UI 初始化
*/
async onStart(params?: any): Promise<void> {
console.log('[UILogin] 初始化', params);
// 获取节点
const node = this.getNode();
if (node) {
this._btnLogin = node.getChildByName('BtnLogin');
this._inputAccount = node.getChildByName('InputAccount')
?.getComponent(EditBox) || null;
}
// 绑定事件
if (this._btnLogin) {
this._btnLogin.on(Node.EventType.TOUCH_END, this.onClickLogin, this);
}
}
/**
* 可选重载: UI 清理
*/
onEnd(): void {
console.log('[UILogin] 清理');
// 解绑事件
if (this._btnLogin) {
this._btnLogin.off(Node.EventType.TOUCH_END, this.onClickLogin, this);
}
}
/**
* 可选重载: 每帧更新
*/
onUpdate(dt: number): void {
// 更新倒计时等逻辑
}
private onClickLogin(): void {
console.log('[UILogin] 点击登录');
// 处理登录逻辑
}
}
```
### 2. 使用 UIMgr 管理 UI
```typescript
import { find } from 'cc';
import { UIMgr } from './Framework/UI/UIMgr';
import { UILogin } from './UI/UILogin';
// 1. 设置 UI 根节点(通常在启动时设置一次)
const canvas = find('Canvas');
if (canvas) {
UIMgr.getInstance().setUIRoot(canvas);
}
// 2. 加载并显示 UI
const loginUI = await UIMgr.getInstance().load(UILogin);
// 3. 传递参数给 UI
const loginUI = await UIMgr.getInstance().load(UILogin, {
username: 'test'
});
// 4. 获取已加载的 UI 实例
const ui = UIMgr.getInstance().get(UILogin);
if (ui) {
ui.hide(); // 隐藏
ui.show(); // 显示
}
// 5. 检查 UI 是否已加载
if (UIMgr.getInstance().has(UILogin)) {
console.log('UILogin 已加载');
}
// 6. 卸载 UI
UIMgr.getInstance().unload(UILogin);
// 或使用类名
UIMgr.getInstance().unload('UILogin');
// 7. 卸载所有 UI(场景切换时)
UIMgr.getInstance().unloadAll();
```
### 3. 在游戏主循环中更新 UI
```typescript
import { Component, _decorator } from 'cc';
import { UIMgr } from './Framework/UI/UIMgr';
const { ccclass } = _decorator;
@ccclass('GameManager')
export class GameManager extends Component {
update(deltaTime: number) {
// 更新所有 UI
UIMgr.getInstance().update(deltaTime);
}
}
```
### 4. UI 状态切换示例
```typescript
// UI 管理器封装
class UIController {
async showLogin(): Promise<void> {
// 隐藏其他 UI
UIMgr.getInstance().unload(UIMain);
// 显示登录 UI
await UIMgr.getInstance().load(UILogin);
}
async showMain(): Promise<void> {
// 隐藏登录 UI
UIMgr.getInstance().unload(UILogin);
// 显示主界面
await UIMgr.getInstance().load(UIMain);
}
async showBattle(): Promise<void> {
// 主界面保持显示,加载战斗 UI
await UIMgr.getInstance().load(UIBattle);
}
}
```
## 🔄 UI 加载流程
```
UIMgr.load(UIClass, params)
1. 检查缓存
├─ 如果已缓存
│ ├─ 调用 ui.show()
│ ├─ 调用 ui.onStart(params)
│ └─ 返回缓存实例
└─ 如果未缓存
2. 创建 UI 实例
3. 调用 ui.onGetUrl() 获取资源路径
4. 通过 ResMgr 加载预制体
5. 实例化预制体节点
6. 添加到 UI 根节点
7. 调用 ui.setNode(node)
8. 缓存 UI 实例
9. 如果有 onUpdate,添加到更新列表
10. 调用 ui.onStart(params)
11. 调用 ui.show()
12. 返回 UI 实例
```
## 📊 UI 生命周期
```
[创建 UI 类实例]
onGetUrl() - 获取资源路径(必须)
[加载预制体]
setNode(node) - 设置节点
onStart(params) - 初始化 UI(可选)
show() - 显示 UI
onUpdate(dt) - 每帧更新(可选)
[卸载 UI]
onEnd() - 清理资源(可选)
[销毁节点和释放资源]
```
## ⚠️ 注意事项
1. **必须重载 onGetUrl()**: 每个 UI 必须明确定义资源路径
2. **UI 根节点设置**: 在加载任何 UI 之前,必须先设置 UI 根节点
3. **缓存机制**: 已加载的 UI 会被缓存,再次加载时直接使用缓存
4. **资源自动管理**: UIMgr 会自动管理资源加载和释放
5. **异步加载**: load 方法是异步的,需要使用 await
6. **类型安全**: 使用泛型确保返回正确的 UI 类型
## 🔍 调试技巧
### 日志输出
```typescript
// UIMgr 内部包含详细日志:
// [UIMgr] 设置UI根节点
// [UIMgr] 开始加载UI: UILogin
// [UIMgr] 从缓存加载UI: UILogin
// [UIMgr] UI加载完成: UILogin
// [UIMgr] 卸载UI: UILogin
```
### 检查 UI 状态
```typescript
const ui = UIMgr.getInstance().get(UILogin);
if (ui) {
console.log(`UI已加载: ${ui.isLoaded()}`);
console.log(`UI显示中: ${ui.isShowing()}`);
}
```
### 常见问题
**问题1**: UI 根节点未设置
```typescript
// 解决: 在加载 UI 前设置根节点
const canvas = find('Canvas');
if (canvas) {
UIMgr.getInstance().setUIRoot(canvas);
}
```
**问题2**: UI 未正确显示
```typescript
// 检查: 资源路径是否正确
onGetUrl(): string {
return 'prefabs/ui/UILogin'; // 确保路径正确
}
```
**问题3**: UI 重复加载
```typescript
// 利用缓存机制:
if (!UIMgr.getInstance().has(UILogin)) {
await UIMgr.getInstance().load(UILogin);
}
```
## 💡 最佳实践
1. **单一职责**: 每个 UI 类只负责一个界面
2. **资源路径统一**: 建议在配置文件中统一管理 UI 资源路径
3. **事件解绑**: 在 onEnd() 中解绑所有事件,避免内存泄漏
4. **参数传递**: 使用 params 参数在加载时传递初始数据
5. **缓存利用**: 对频繁切换的 UI,利用缓存避免重复加载
6. **及时卸载**: 不再使用的 UI 及时卸载,释放资源
## 🎯 应用场景
- ✅ 登录界面
- ✅ 主界面
- ✅ 战斗界面
- ✅ 设置界面
- ✅ 背包界面
- ✅ 商店界面
- ✅ 对话框
- ✅ 提示框
## 📚 扩展功能
### UI 层级管理
```typescript
// 可以扩展 UIMgr 支持 UI 层级
enum UILayer {
Background = 0, // 背景层
Normal = 100, // 普通层
Popup = 200, // 弹窗层
Top = 300 // 顶层
}
// 在加载 UI 时指定层级
ui.getNode()?.setSiblingIndex(UILayer.Popup);
```
### UI 动画
```typescript
// 在 onStart 中添加打开动画
async onStart(): Promise<void> {
const node = this.getNode();
if (node) {
// 缩放动画
node.scale = Vec3.ZERO;
tween(node)
.to(0.3, { scale: Vec3.ONE }, { easing: 'backOut' })
.start();
}
}
// 在关闭时添加动画
async close(): Promise<void> {
const node = this.getNode();
if (node) {
await new Promise(resolve => {
tween(node)
.to(0.2, { scale: Vec3.ZERO })
.call(resolve)
.start();
});
}
UIMgr.getInstance().unload(this.constructor as any);
}
```

View File

@@ -0,0 +1,124 @@
import { Node } from 'cc';
/**
* UI基类
* 职责:
* - 定义UI的基础接口和生命周期
* - 管理UI根节点
* - 提供显示/隐藏控制
*
* 所有UI必须继承此类并实现onGetUrl方法
*/
export abstract class UIBase {
/** UI根节点 */
protected _node: Node | null = null;
/** UI是否已加载 */
protected _isLoaded: boolean = false;
/** UI是否显示中 */
protected _isShowing: boolean = false;
/**
* 获取UI资源路径 (必须重载)
* @returns UI预制体路径
* @example
* onGetUrl(): string {
* return 'UI/Login/UILogin';
* }
*/
abstract onGetUrl(): string;
/**
* UI开始时调用 (可选重载)
* 在UI预制体加载完成后调用
* 可以在此方法中初始化UI数据、绑定事件等
* @param params 传入的参数
* @example
* onStart(params?: any): void {
* console.log('UI初始化', params);
* // 绑定按钮事件
* this.bindEvents();
* }
*/
onStart?(params?: any): void | Promise<void>;
/**
* UI结束时调用 (可选重载)
* 在UI被卸载前调用
* 可以在此方法中清理资源、解绑事件等
* @example
* onEnd(): void {
* console.log('UI清理');
* // 解绑按钮事件
* this.unbindEvents();
* }
*/
onEnd?(): void;
/**
* UI更新 (可选重载)
* 在每帧调用(仅当UI显示时)
* @param dt 距离上一帧的时间(秒)
* @example
* onUpdate(dt: number): void {
* // 更新倒计时
* this.updateTimer(dt);
* }
*/
onUpdate?(dt: number): void;
/**
* 设置UI根节点
* 由UIMgr在加载完成后调用
* @param node UI根节点
*/
setNode(node: Node): void {
this._node = node;
this._isLoaded = true;
}
/**
* 获取UI根节点
* @returns UI根节点,如果未加载则返回null
*/
getNode(): Node | null {
return this._node;
}
/**
* 显示UI
*/
show(): void {
if (this._node) {
this._node.active = true;
this._isShowing = true;
}
}
/**
* 隐藏UI
*/
hide(): void {
if (this._node) {
this._node.active = false;
this._isShowing = false;
}
}
/**
* 检查UI是否显示中
* @returns true表示正在显示,false表示已隐藏
*/
isShowing(): boolean {
return this._isShowing;
}
/**
* 检查UI是否已加载
* @returns true表示已加载,false表示未加载
*/
isLoaded(): boolean {
return this._isLoaded;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "0a812118-97d6-470b-b73d-933bc31fb3d4",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,293 @@
import { Node, Prefab, instantiate } from 'cc';
import { UIBase } from './UIBase';
import { ResMgr } from '../ResMgr/ResMgr';
/**
* UI管理器
* 职责:
* - 管理所有UI的加载、显示、隐藏和销毁
* - 维护UI缓存,避免重复加载
* - 管理UI的生命周期
* - 提供UI更新机制
*/
export class UIMgr {
private static _instance: UIMgr;
/** 已加载的UI实例缓存 */
private _uiCache: Map<string, UIBase> = new Map();
/** UI父节点(Canvas) */
private _uiRoot: Node | null = null;
/** 需要更新的UI列表 */
private _updateList: UIBase[] = [];
/**
* 获取单例
*/
static getInstance(): UIMgr {
if (!this._instance) {
this._instance = new UIMgr();
}
return this._instance;
}
/**
* 设置UI根节点
* @param root Canvas节点或UI容器节点
* @example
* const canvas = find('Canvas');
* if (canvas) {
* UIMgr.getInstance().setUIRoot(canvas);
* }
*/
setUIRoot(root: Node): void {
this._uiRoot = root;
console.log('[UIMgr] 设置UI根节点');
}
/**
* 加载并显示UI
* @param uiClass UI类
* @param params 传递给onStart的参数
* @returns UI实例
* @example
* const loginUI = await UIMgr.getInstance().load(UILogin, { username: 'test' });
*/
async load<T extends UIBase>(
uiClass: new () => T,
params?: any
): Promise<T> {
const className = uiClass.name;
// 检查缓存
let ui = this._uiCache.get(className) as T;
if (ui) {
console.log(`[UIMgr] 从缓存加载UI: ${className}`);
ui.show();
if (ui.onStart) {
await ui.onStart(params);
}
return ui;
}
// 创建UI实例
ui = new uiClass();
// 获取UI资源路径
const url = ui.onGetUrl();
if (!url) {
console.error(`[UIMgr] UI未定义资源路径: ${className}`);
throw new Error(`UI未定义资源路径: ${className}`);
}
console.log(`[UIMgr] 开始加载UI: ${className} (${url})`);
// 通过ResMgr加载预制体
try {
const prefab = await ResMgr.getInstance().load<Prefab>(
'resources',
url,
Prefab
);
// 实例化预制体
const node = instantiate(prefab);
// 添加到UI根节点
if (this._uiRoot) {
node.setParent(this._uiRoot);
} else {
console.warn(`[UIMgr] UI根节点未设置,UI将无父节点: ${className}`);
}
// 设置UI节点
ui.setNode(node);
// 缓存UI
this._uiCache.set(className, ui);
// 如果UI有onUpdate方法,添加到更新列表
if (ui.onUpdate) {
this._updateList.push(ui);
}
// 调用onStart生命周期
if (ui.onStart) {
await ui.onStart(params);
}
// 显示UI
ui.show();
console.log(`[UIMgr] UI加载完成: ${className}`);
return ui;
} catch (error) {
console.error(`[UIMgr] 加载UI失败: ${className}`, error);
throw error;
}
}
/**
* 卸载UI
* @param uiClass UI类或类名
* @example
* UIMgr.getInstance().unload(UILogin);
* // 或
* UIMgr.getInstance().unload('UILogin');
*/
unload(uiClass: (new () => UIBase) | string): void {
const className = typeof uiClass === 'string'
? uiClass
: uiClass.name;
const ui = this._uiCache.get(className);
if (!ui) {
console.warn(`[UIMgr] UI未加载,无法卸载: ${className}`);
return;
}
console.log(`[UIMgr] 卸载UI: ${className}`);
// 调用onEnd生命周期
if (ui.onEnd) {
ui.onEnd();
}
// 从更新列表移除
const index = this._updateList.indexOf(ui);
if (index !== -1) {
this._updateList.splice(index, 1);
}
// 销毁节点
const node = ui.getNode();
if (node && node.isValid) {
node.destroy();
}
// 从缓存移除
this._uiCache.delete(className);
// 释放资源
const url = ui.onGetUrl();
if (url) {
ResMgr.getInstance().release('resources', url);
}
}
/**
* 获取已加载的UI实例
* @param uiClass UI类或类名
* @returns UI实例,如果未加载则返回null
* @example
* const loginUI = UIMgr.getInstance().get(UILogin);
* if (loginUI) {
* loginUI.show();
* }
*/
get<T extends UIBase>(uiClass: (new () => T) | string): T | null {
const className = typeof uiClass === 'string'
? uiClass
: uiClass.name;
return (this._uiCache.get(className) as T) || null;
}
/**
* 检查UI是否已加载
* @param uiClass UI类或类名
* @returns true表示已加载,false表示未加载
* @example
* if (UIMgr.getInstance().has(UILogin)) {
* console.log('登录UI已加载');
* }
*/
has(uiClass: (new () => UIBase) | string): boolean {
const className = typeof uiClass === 'string'
? uiClass
: uiClass.name;
return this._uiCache.has(className);
}
/**
* 更新所有需要更新的UI
* 应在主循环中每帧调用
* @param dt 距离上一帧的时间(秒)
* @example
* // 在主场景的update方法中调用
* update(dt: number) {
* UIMgr.getInstance().update(dt);
* }
*/
update(dt: number): void {
for (const ui of this._updateList) {
if (ui.isShowing() && ui.onUpdate) {
ui.onUpdate(dt);
}
}
}
/**
* 卸载所有UI
* @example
* // 在场景切换或退出游戏时调用
* UIMgr.getInstance().unloadAll();
*/
unloadAll(): void {
console.log(`[UIMgr] 卸载所有UI`);
const classNames = Array.from(this._uiCache.keys());
for (const className of classNames) {
this.unload(className);
}
}
/**
* 获取当前已加载UI的数量
* @returns UI数量
*/
getUICount(): number {
return this._uiCache.size;
}
/**
* 显示指定UI(不重新加载)
* @param uiClass UI类或类名
* @example
* UIMgr.getInstance().show(UILogin);
*/
show(uiClass: (new () => UIBase) | string): void {
const className = typeof uiClass === 'string'
? uiClass
: uiClass.name;
const ui = this._uiCache.get(className);
if (ui) {
ui.show();
} else {
console.warn(`[UIMgr] UI未加载,无法显示: ${className}`);
}
}
/**
* 隐藏指定UI(不卸载)
* @param uiClass UI类或类名
* @example
* UIMgr.getInstance().hide(UILogin);
*/
hide(uiClass: (new () => UIBase) | string): void {
const className = typeof uiClass === 'string'
? uiClass
: uiClass.name;
const ui = this._uiCache.get(className);
if (ui) {
ui.hide();
} else {
console.warn(`[UIMgr] UI未加载,无法隐藏: ${className}`);
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "bb73ed34-9565-47f3-8ec9-e10367ef52f4",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,247 @@
import { _decorator, Component, Node, Label, Button, find } from 'cc';
import { UIBase } from './UIBase';
import { UIMgr } from './UIMgr';
const { ccclass, property } = _decorator;
/**
* UI使用示例
*
* 本文件展示如何使用UI系统:
* 1. 创建自定义UI类
* 2. 加载和显示UI
* 3. 更新UI
* 4. 卸载UI
*/
// ============================================
// 示例1: 简单的UI类
// ============================================
/**
* 登录UI示例
*/
export class UILogin extends UIBase {
/**
* 返回UI预制体路径
*/
onGetUrl(): string {
return 'UI/Login/UILogin';
}
/**
* UI初始化
*/
onStart(params?: any): void {
console.log('[UILogin] 初始化', params);
// 获取节点
const node = this.getNode();
if (!node) return;
// 查找按钮并绑定事件
const btnLogin = node.getChildByName('BtnLogin');
if (btnLogin) {
const button = btnLogin.getComponent(Button);
if (button) {
button.node.on(Button.EventType.CLICK, this.onLoginClick, this);
}
}
}
/**
* UI清理
*/
onEnd(): void {
console.log('[UILogin] 清理');
// 解绑事件
const node = this.getNode();
if (!node) return;
const btnLogin = node.getChildByName('BtnLogin');
if (btnLogin) {
btnLogin.off(Button.EventType.CLICK, this.onLoginClick, this);
}
}
/**
* 登录按钮点击
*/
private onLoginClick(): void {
console.log('[UILogin] 点击登录按钮');
// 执行登录逻辑...
}
}
// ============================================
// 示例2: 带更新的UI类
// ============================================
/**
* 游戏主界面UI示例
* 包含倒计时等需要每帧更新的逻辑
*/
export class UIMain extends UIBase {
private _timeLeft: number = 60;
private _labelTime: Label | null = null;
onGetUrl(): string {
return 'UI/Main/UIMain';
}
onStart(): void {
console.log('[UIMain] 初始化');
const node = this.getNode();
if (!node) return;
// 获取时间Label
const timeNode = node.getChildByName('LabelTime');
if (timeNode) {
this._labelTime = timeNode.getComponent(Label);
}
this.updateTimeDisplay();
}
/**
* 每帧更新
*/
onUpdate(dt: number): void {
// 更新倒计时
this._timeLeft -= dt;
if (this._timeLeft < 0) {
this._timeLeft = 0;
}
this.updateTimeDisplay();
}
/**
* 更新时间显示
*/
private updateTimeDisplay(): void {
if (this._labelTime) {
this._labelTime.string = `剩余时间: ${Math.floor(this._timeLeft)}s`;
}
}
}
// ============================================
// 示例3: 在Component中使用UI系统
// ============================================
/**
* UI管理器使用示例组件
*/
@ccclass('UIMgrExample')
export class UIMgrExample extends Component {
start() {
// 设置UI根节点
const canvas = find('Canvas');
if (canvas) {
UIMgr.getInstance().setUIRoot(canvas);
}
// 演示UI加载和使用
this.testUISystem();
}
update(dt: number) {
// 每帧更新UI系统
UIMgr.getInstance().update(dt);
}
/**
* 测试UI系统
*/
private async testUISystem() {
console.log('========== UI系统测试开始 ==========');
try {
// 1. 加载登录UI
console.log('\n--- 测试1: 加载登录UI ---');
const loginUI = await UIMgr.getInstance().load(UILogin, {
username: 'player1'
});
console.log('登录UI加载成功:', loginUI);
// 2. 检查UI是否存在
console.log('\n--- 测试2: 检查UI状态 ---');
console.log('是否已加载:', UIMgr.getInstance().has(UILogin));
console.log('是否显示中:', loginUI.isShowing());
// 3. 隐藏和显示UI
console.log('\n--- 测试3: 隐藏和显示 ---');
setTimeout(() => {
console.log('隐藏登录UI');
UIMgr.getInstance().hide(UILogin);
}, 2000);
setTimeout(() => {
console.log('显示登录UI');
UIMgr.getInstance().show(UILogin);
}, 4000);
// 4. 加载主界面UI
console.log('\n--- 测试4: 加载主界面UI ---');
setTimeout(async () => {
const mainUI = await UIMgr.getInstance().load(UIMain);
console.log('主界面UI加载成功:', mainUI);
console.log('当前UI数量:', UIMgr.getInstance().getUICount());
}, 6000);
// 5. 卸载UI
console.log('\n--- 测试5: 卸载UI ---');
setTimeout(() => {
console.log('卸载登录UI');
UIMgr.getInstance().unload(UILogin);
console.log('当前UI数量:', UIMgr.getInstance().getUICount());
}, 8000);
// 6. 卸载所有UI
console.log('\n--- 测试6: 卸载所有UI ---');
setTimeout(() => {
console.log('卸载所有UI');
UIMgr.getInstance().unloadAll();
console.log('当前UI数量:', UIMgr.getInstance().getUICount());
}, 10000);
} catch (error) {
console.error('UI系统测试失败:', error);
}
console.log('\n========== UI系统测试完成 ==========');
}
}
// ============================================
// 使用说明
// ============================================
/**
* 基本使用流程:
*
* 1. 创建UI类:
* export class MyUI extends UIBase {
* onGetUrl(): string {
* return 'UI/MyUI';
* }
* }
*
* 2. 设置UI根节点:
* UIMgr.getInstance().setUIRoot(canvas);
*
* 3. 加载并显示UI:
* const ui = await UIMgr.getInstance().load(MyUI);
*
* 4. 在主循环中更新:
* update(dt: number) {
* UIMgr.getInstance().update(dt);
* }
*
* 5. 卸载UI:
* UIMgr.getInstance().unload(MyUI);
*/

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "d8fecb48-938f-489a-83e5-510c8247bc09",
"files": [],
"subMetas": {},
"userData": {}
}