优化Framework.UI新增便捷接口

This commit is contained in:
janing
2025-12-14 23:35:54 +08:00
parent d530b48e34
commit 1d91daa726
5 changed files with 285 additions and 1742 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -123,9 +123,16 @@ export class UILogin extends UIBase {
/** /**
* 必须重载: 返回 UI 资源路径 * 必须重载: 返回 UI 资源路径
*
* 编写规则:
* 1. 普通资源路径: 'prefabs/ui/UILogin'
* 2. Bundle资源路径: '[bundle名]://资源路径'
* 示例: 'ui-bundle://prefabs/UILogin'
*/ */
onGetUrl(): string { onGetUrl(): string {
return 'prefabs/ui/UILogin'; return 'prefabs/ui/UILogin';
// 或使用 bundle 方式:
// return 'ui-bundle://prefabs/UILogin';
} }
/** /**
@@ -323,6 +330,8 @@ onEnd() - 清理资源(可选)
## ⚠️ 注意事项 ## ⚠️ 注意事项
1. **必须重载 onGetUrl()**: 每个 UI 必须明确定义资源路径 1. **必须重载 onGetUrl()**: 每个 UI 必须明确定义资源路径
- 普通资源路径格式: `'prefabs/ui/UILogin'`
- Bundle资源路径格式: `'[bundle名]://资源路径'` (例如: `'ui-bundle://prefabs/UILogin'`)
2. **UI 根节点设置**: 在加载任何 UI 之前,必须先设置 UI 根节点 2. **UI 根节点设置**: 在加载任何 UI 之前,必须先设置 UI 根节点
3. **缓存机制**: 已加载的 UI 会被缓存,再次加载时直接使用缓存 3. **缓存机制**: 已加载的 UI 会被缓存,再次加载时直接使用缓存
4. **资源自动管理**: UIMgr 会自动管理资源加载和释放 4. **资源自动管理**: UIMgr 会自动管理资源加载和释放
@@ -367,7 +376,11 @@ if (canvas) {
```typescript ```typescript
// 检查: 资源路径是否正确 // 检查: 资源路径是否正确
onGetUrl(): string { onGetUrl(): string {
return 'prefabs/ui/UILogin'; // 确保路径正确 // 普通资源路径
return 'prefabs/ui/UILogin';
// 或使用 Bundle 资源路径
// return 'ui-bundle://prefabs/UILogin';
} }
``` ```
@@ -383,6 +396,8 @@ if (!UIMgr.getInstance().has(UILogin)) {
1. **单一职责**: 每个 UI 类只负责一个界面 1. **单一职责**: 每个 UI 类只负责一个界面
2. **资源路径统一**: 建议在配置文件中统一管理 UI 资源路径 2. **资源路径统一**: 建议在配置文件中统一管理 UI 资源路径
- 对于需要分包加载的 UI,使用 Bundle 路径格式: `'[bundle名]://资源路径'`
- 对于通用 UI,使用普通路径格式: `'资源路径'`
3. **事件解绑**: 在 onEnd() 中解绑所有事件,避免内存泄漏 3. **事件解绑**: 在 onEnd() 中解绑所有事件,避免内存泄漏
4. **参数传递**: 使用 params 参数在加载时传递初始数据 4. **参数传递**: 使用 params 参数在加载时传递初始数据
5. **缓存利用**: 对频繁切换的 UI,利用缓存避免重复加载 5. **缓存利用**: 对频繁切换的 UI,利用缓存避免重复加载

View File

@@ -0,0 +1,11 @@
{
"ver": "1.0.1",
"importer": "text",
"imported": true,
"uuid": "fbfe85a1-0fe1-4ac7-b004-36c370c6a4eb",
"files": [
".json"
],
"subMetas": {},
"userData": {}
}

View File

@@ -1,4 +1,4 @@
import { Node } from 'cc'; import { Node, Component, Button } from 'cc';
/** /**
* UI基类 * UI基类
@@ -121,4 +121,67 @@ export abstract class UIBase {
isLoaded(): boolean { isLoaded(): boolean {
return this._isLoaded; return this._isLoaded;
} }
/**
* 查找子节点并获取组件
* @param path 节点路径,支持多层级查找(如: 'mid/input_account')
* @param componentType 组件类型
* @returns 组件实例,未找到则返回null
* @example
* const editBox = this.GetChild('mid/input_account', EditBox);
* const button = this.GetChild('btn_login', Button);
*/
protected GetChild<T extends Component>(path: string, componentType: { new(): T }): T | null {
if (!this._node) {
console.error('[UIBase] GetChild失败: UI根节点不存在');
return null;
}
const childNode = this._node.getChildByPath(path);
if (!childNode) {
console.error(`[UIBase] GetChild失败: 未找到节点 ${path}`);
return null;
}
const component = childNode.getComponent(componentType);
if (!component) {
console.error(`[UIBase] GetChild失败: 节点 ${path} 未挂载 ${componentType.name} 组件`);
return null;
}
return component;
}
/**
* 设置按钮点击事件
* @param button Button组件或包含Button组件的Node
* @param callback 点击回调函数
* @param target 回调函数的this指向
* @example
* const btn = this.GetChild('btn_login', Button);
* this.SetClick(btn, this.onLoginClick, this);
*/
protected SetClick(button: Button | Node | null, callback: () => void, target?: any): void {
if (!button) {
console.error('[UIBase] SetClick失败: button为null');
return;
}
let targetNode: Node | null = null;
// 判断是Button组件还是Node
if (button instanceof Button) {
targetNode = button.node;
} else if (button instanceof Node) {
targetNode = button;
}
if (!targetNode) {
console.error('[UIBase] SetClick失败: 无法获取目标节点');
return;
}
// 绑定点击事件
targetNode.on(Node.EventType.TOUCH_END, callback, target);
}
} }

View File

@@ -82,12 +82,14 @@ export class UIMgr {
} }
console.log(`[UIMgr] 开始加载UI: ${className} (${url})`); console.log(`[UIMgr] 开始加载UI: ${className} (${url})`);
const args = url.split('://')
const bundleName = args[0];
const resourcePath = args[1];
// 通过ResMgr加载预制体 // 通过ResMgr加载预制体
try { try {
const prefab = await ResMgr.getInstance().load<Prefab>( const prefab = await ResMgr.getInstance().load<Prefab>(
'resources', bundleName,
url, resourcePath,
Prefab Prefab
); );