# StrayFog 框架 UI 开发指南 ## 一、窗口开发 ### 1.1 创建模板 ```csharp [HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/MyWindow/MyWindow.prefab")] [HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Dynamic)] public class MyWindow : AbsHFUIWindow { private SFUI_Button BtnClose; protected override void OnRunAwake() { base.OnRunAwake(); BtnClose = FindUICtrlByName("BtnClose"); BtnClose.OnAddClickListener += OnBtnClose; } protected override void OnOpen(Action _onOpenComplete) { base.OnOpen(_onOpenComplete); RefreshUI(); } private void OnBtnClose(GameObject go) => CloseWindow(); private void RefreshUI() { } } ``` ### 1.2 生命周期 | 方法 | 调用时机 | 推荐操作 | |-----|---------|---------| | `OnRunAwake` | 创建时一次 | 绑定 UI 事件、初始化滚动列表 `BindEvent` | | `OnOpen` | 每次打开 | 注册 TC 事件、调用 `ShowView()` 刷新数据 | | `OnClose` | 每次关闭 | 取消 TC 事件 | **关键原则**: - **绑定类操作**(如 `BindEvent`)放在 `OnRunAwake`,只需执行一次 - **刷新类操作**(如 `ShowView`)放在 `OnOpen`,每次打开都需执行 ### 1.3 窗口操作 ```csharp // 打开 HFFunCatalogue.UIManager.OpenWindow(); // 关闭 HFFunCatalogue.UIManager.CloseWindow(); ``` --- ## 二、事件绑定 | 事件类型 | 绑定位置 | 是否需要 `-=` | |---------|---------|--------------| | UI 按钮/拖拽 | `OnRunAwake` | 不需要 | | 全局 TC 事件 | `OnOpen`/`OnClose` | 需要 | --- ## 三、常用组件 ### 3.1 按钮 ```csharp SFUI_Button btn = GetComponent(); btn.OnAddClickListener += OnBtnClick; btn.SetSelfGray(true); ``` ### 3.2 文本 ```csharp SFUI_TextMeshProUGUI txt = GetComponent(); txt.text = "Hello"; ``` ### 3.3 图片 ```csharp SFUI_Image img = GetComponent(); img.HFSetSprite(/* atlasName */, "Icon_Player", /* languageRoot */); ``` ### 3.4 滚动列表(核心) **生命周期正确划分示例**: ```csharp private SFUI_ScrollRect m_ScrollList; private List m_ItemList; protected override void OnRunAwake() { base.OnRunAwake(); m_ScrollList = FindUICtrlByName("ScrollList"); // ✅ 绑定事件放在 Awake(一次绑定,永久生效) m_ScrollList.BindEvent( () => m_ItemList.Count, // 数据源闭包 (idx) => itemPrefab.gameObject, // 生成预制体 OnUpdateItem, // 更新回调 (item) => item.gameObject.HFGetOrAddSimulateBehaviour() // 获取组件 ); } protected override void OnOpen(Action _onOpenComplete) { base.OnOpen(_onOpenComplete); m_ItemList = GetDataFromServer(); // 获取最新数据 m_ScrollList.ShowView(); // ✅ 刷新显示放在 Open } private void OnUpdateItem(int index, AbsHFUIWindow window) { ItemSlot slot = window as ItemSlot; slot.SetData(m_ItemList[index]); } ``` **设计要点**: - `BindEvent` 在 `OnRunAwake` 中执行,建立绑定机制 - `ShowView` 在 `OnOpen` 中执行,触发数据刷新 - 数据源通过闭包引用,`ShowView` 时自动获取最新数据 --- ## 四、对象池 | 场景 | 推荐方式 | |-----|---------| | 滚动列表 | `SFUI_ScrollRect.BindEvent`(内置池) | | 固定栏(装备/技能) | `HFSimulateBehaviourPool` | --- ## 五、子组件 ### 5.1 多态基类 ```csharp public abstract class AbsListItem : AbsHFUIWindow { protected SFUI_Button m_BtnItem; protected Action m_OnSelect; protected override void OnRunAwake() { base.OnRunAwake(); m_BtnItem = gameObject.GetComponent(); m_BtnItem.OnAddClickListener += OnBtnClick; } public virtual void SetData(T data, Action onSelect = null) { m_OnSelect = onSelect; OnDataChanged(data); } protected abstract void OnDataChanged(T data); private void OnBtnClick(GameObject go) => m_OnSelect?.Invoke(m_CurrentData); } // 子类 public class CardItem : AbsListItem { protected override void OnDataChanged(CardData data) { } } ``` --- ## 六、开发规范 ### 6.1 文件路径 #### 6.1.1 核心资源路径 | 类型 | 路径 | 说明 | |-----|------|------| | **窗口脚本** | `Assets/Game/GameHFScripte/GameFunction/UIWindows/{WindowName}/` | 窗口逻辑脚本存放目录 | | **窗口预制体** | `Assets/Game/GameHFResource/CN/UIWindows/{WindowName}/` | UI 窗口预制体存放目录 | | **图标图集** | `Assets/Game/GameHFResource/CN/SpriteAtlas/{AtlasName}/` | SpriteAtlas 图集资源 | | **字体资源** | `Assets/Game/GameHFResource/CN/Fonts/` | 字体文件存放目录 | #### 6.1.2 工具脚本路径 | 工具名称 | 路径 | 职责 | |---------|------|------| | **UIPrefabGenerator** | `Assets/Editor/Command/UIPrefabGenerator.cs` | JSON 转 UI 预制体 | | **UIPrefabToJson** | `Assets/Editor/Command/UIPrefabToJson.cs` | 预制体转 JSON | | **RemoteCommand** | `Assets/Editor/Command/RemoteCommand.cs` | 外部命令接口 | | **ExternalCommandListener** | `Assets/Editor/Command/ExternalCommandListener.cs` | 外部命令监听器 | #### 6.1.3 文档路径 | 文档名称 | 路径 | |---------|------| | UI 开发指南 | [UI窗口系统/开发指南.md](开发指南.md) | | UI 界面拼接设计指南 | [UI窗口系统/界面拼接.md](界面拼接.md) | #### 6.1.4 命令触发路径 - **触发文件**: `{ProjectRoot}/Trigger_Command.txt` - **JSON 配置**: `Assets/Editor/UI/{WindowName}.json` ### 6.2 性能优化 - 使用对象池复用 UI 元素 - 将图标打包到 SpriteAtlas - 滚动列表用 `SFUI_ScrollRect.BindEvent` --- **版本**: v1.1 **适用**: StrayFog 框架 UI 开发人员 --- ## 文档关联 > 当本文档发生变更时,应同步检查以下关联文档,避免信息不一致。 | 文档 | 关联原因 | |---|---| | [UI 窗口系统入口](README.md) | 本文件是 UI 窗口系统模块的子文档 | | [UI 界面拼接设计指南](界面拼接.md) | 界面拼接是 UI 开发的补充设计指南 | | [UI 拼接工具](../编辑器工具/UI拼接工具.md) | JSON 驱动 UI 生成工具说明 | | [事件系统](../事件系统/README.md) | UI 事件订阅和释放规范 | | [对象池与运行时对象管理](../内存对象管理/README.md) | UI 元素复用相关 | | [资源管理](../资源管理/README.md) | UI 资源加载依赖资源管理 | | [modules/模块索引.md](../../模块索引.md) | 模块索引是项目知识总入口 | | [rules/10-架构说明.md](../../../rules/10-架构说明.md) | 架构说明定义总体分层和依赖方向 | | [rules/20-开发规则.md](../../../rules/20-开发规则.md) | UI 命名与编码规范互相引用 | | [rules/30-模块登记规则.md](../../../rules/30-模块登记规则.md) | 模块登记规则定义分类和状态口径 |