整理UI文档:创建UI文件夹,更新README

This commit is contained in:
Shiliang
2026-05-22 16:58:41 +08:00
parent 42fcb5664a
commit 93b718b230
4 changed files with 325 additions and 353 deletions

View File

@@ -0,0 +1,154 @@
# 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<SFUI_Button>("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事件 |
| `OnOpen` | 每次打开 | 注册TC事件、刷新数据 |
| `OnClose` | 每次关闭 | 取消TC事件 |
### 1.3 窗口操作
```csharp
// 打开
HFFunCatalogue.UIManager.OpenWindow<MyWindow>();
// 关闭
HFFunCatalogue.UIManager.CloseWindow<MyWindow>();
```
---
## 二、事件绑定
| 事件类型 | 绑定位置 | 是否需要 `-=` |
|---------|---------|--------------|
| UI按钮/拖拽 | `OnRunAwake` | 不需要 |
| 全局TC事件 | `OnOpen`/`OnClose` | 需要 |
---
## 三、常用组件
### 3.1 按钮
```csharp
SFUI_Button btn = GetComponent<SFUI_Button>();
btn.OnAddClickListener += OnBtnClick;
btn.SetSelfGray(true);
```
### 3.2 文本
```csharp
SFUI_TextMeshProUGUI txt = GetComponent<SFUI_TextMeshProUGUI>();
txt.text = "Hello";
```
### 3.3 图片
```csharp
SFUI_Image img = GetComponent<SFUI_Image>();
img.HFSetSprite(/* atlasName */, "Icon_Player", /* languageRoot */);
```
### 3.4 滚动列表(核心)
```csharp
SFUI_ScrollRect scroll = GetComponent<SFUI_ScrollRect>();
scroll.BindEvent(
() => itemList.Count,
(idx) => itemPrefab.gameObject,
OnUpdateItem,
(item) => item.gameObject.HFGetOrAddSimulateBehaviour<ItemSlot>()
);
scroll.ShowView();
```
---
## 四、对象池
| 场景 | 推荐方式 |
|-----|---------|
| 滚动列表 | `SFUI_ScrollRect.BindEvent`(内置池) |
| 固定栏(装备/技能) | `HFSimulateBehaviourPool<T>` |
---
## 五、子组件
### 5.1 多态基类
```csharp
public abstract class AbsListItem<T> : AbsHFUIWindow
{
protected SFUI_Button m_BtnItem;
protected Action<T> m_OnSelect;
protected override void OnRunAwake()
{
base.OnRunAwake();
m_BtnItem = gameObject.GetComponent<SFUI_Button>();
m_BtnItem.OnAddClickListener += OnBtnClick;
}
public virtual void SetData(T data, Action<T> 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<CardData>
{
protected override void OnDataChanged(CardData data) { }
}
```
---
## 六、开发规范
### 6.1 文件路径
| 类型 | 路径 |
|-----|------|
| 脚本 | `Assets/Game/GameHFScripte/GameFunction/UIWindows/{Name}/` |
| 预制体 | `Assets/Game/GameHFResource/CN/UIWindows/{Name}/` |
| 图片 | `Assets/Game/GameHFResource/CN/SpriteAtlas/{Name}/` |
### 6.2 性能优化
- 使用对象池复用UI元素
- 将图标打包到SpriteAtlas
- 滚动列表用 `SFUI_ScrollRect.BindEvent`
---
**版本**: v1.0
**适用**: StrayFog框架开发人员

View File

@@ -0,0 +1,167 @@
# UI界面拼接设计指南
## 一、界面结构设计原则
### 1.1 模块化拆分
将界面按功能划分为独立模块:
| 模块类型 | 功能定位 | 示例 |
|---------|---------|------|
| **信息展示区** | 显示玩家状态、资源等静态信息 | 顶部信息栏、左侧状态栏 |
| **功能入口区** | 提供功能按钮入口 | 中央功能区、底部快捷栏 |
| **交互面板区** | 可展开/收起的功能面板 | 右侧功能面板、顶部按钮区 |
| **输入输出区** | 用户输入和系统反馈 | 聊天输入框、提示信息 |
### 1.2 经典布局模式
```
┌─────────────────────────────────────────────────────┐
│ TopArea (信息展示 + 可收起功能按钮) │
├──────────┬───────────────────────┬──────────────────┤
│ Left │ │ Right │
│ Area │ CenterArea │ Area │
│ (状态) │ (核心功能入口) │ (功能面板) │
│ │ │ │
├──────────┴───────────────────────┴──────────────────┤
│ BottomArea (快捷功能 + 状态信息 + 输入) │
└─────────────────────────────────────────────────────┘
```
---
## 二、组件拆分方法
### 2.1 基础组件识别
| 组件类型 | 识别特征 | 处理方式 |
|---------|---------|---------|
| **按钮** | 可点击、有交互反馈 | 使用 `SFUI_Button` |
| **文本** | 静态/动态文字显示 | 使用 `SFUI_TextMeshProUGUI` |
| **图片** | 图标、背景图 | 使用 `SFUI_Image` |
| **进度条** | HP、MP、经验等 | 使用 `SFUI_Slider` |
| **列表** | 可滚动的项目列表 | 使用 `SFUI_ScrollRect` |
### 2.2 复合组件封装
将功能相关的基础组件组合为复合组件,便于复用和维护:
**设计原则**
- 将同一功能模块的组件封装在一起(如玩家头像+血条+蓝条)
- 提供统一的数据设置接口
- 保持组件之间的逻辑独立性
---
## 三、预制体层级规范
### 3.1 标准层级结构
```
WindowName (RectTransform)
├── ModuleName (RectTransform) # 模块容器
│ ├── ComponentName (SFUI_*) # 功能组件
│ ├── SubModule (RectTransform) # 子模块
│ └── CollapsibleArea (RectTransform) # 可收起区域
└── BtnCollapse (SFUI_Button) # 收起控制按钮
```
### 3.2 命名规范
| 类型 | 命名规则 | 示例 |
|-----|---------|------|
| 模块容器 | PascalCase + Area | `TopArea` |
| 功能组件 | PascalCase | `BtnCollapseTop` |
| 可收起区域 | PascalCase + FuncArea | `TopFuncArea` |
| 状态变量 | m_ + PascalCase | `m_IsTopCollapsed` |
---
## 四、收起/展开功能设计
### 4.1 功能定义
| 按钮 | 控制区域 | 用途 |
|-----|---------|------|
| `BtnCollapseTop` | 顶部功能按钮区 | 收起/展开顶部按钮群 |
| `BtnCollapseRight` | 右侧功能面板区 | 收起/展开右侧功能面板 |
### 4.2 设计要点
**状态管理**:每个可收起区域需要一个布尔状态变量来记录当前收起/展开状态。
**交互逻辑**
1. 点击收起按钮时,切换对应区域的显示/隐藏状态
2. 同时切换按钮图标(收起时显示展开图标,展开时显示收起图标)
**布局要求**
- 收起按钮应放置在对应区域的边缘位置,便于用户找到
- 收起区域内的所有元素应作为一个整体进行显示/隐藏控制
- 收起状态应在窗口生命周期内保持记忆
---
## 五、实际案例:主界面拼接
### 5.1 模块化设计思想
**核心原则**:将界面按功能边界划分为独立模块,模块内可嵌套子模块。
**模块归类方法**
1. **一级模块**:按空间位置划分(顶部、左侧、中央、右侧、底部)
2. **二级模块**:按功能类型划分(信息展示区、功能按钮区、输入输出区)
3. **三级模块**:按具体功能划分(玩家头像、资源显示、功能按钮群)
**层级关系示例**
```
Window
├── TopArea (一级:位置)
│ ├── InfoPanel (二级:信息展示)
│ │ └── TxtWelcome (三级:具体组件)
│ └── FuncButtons (二级:功能按钮)
│ └── BtnUpload (三级:具体按钮)
└── LeftArea (一级:位置)
└── PlayerPortrait (二级:复合组件)
├── ImgAvatar (三级:头像)
└── BarHP (三级:血条)
```
**设计要点**
- 同一功能域内的元素归为同一模块(如头像、血条、蓝条归为玩家状态模块)
- 独立交互功能作为独立模块(如收起按钮单独作为控制模块)
- 可收起区域作为独立子模块,便于统一控制显示/隐藏
---
## 六、界面拼接流程
### 6.1 设计阶段
1. **需求分析**:明确界面功能和交互需求
2. **模块划分**:将界面拆分为独立功能模块
3. **层级设计**:设计预制体层级结构
### 6.2 开发阶段
1. **组件创建**:创建基础组件和复合组件
2. **预制体搭建**:按层级结构搭建预制体
3. **脚本编写**:实现交互逻辑和收起/展开功能
### 6.3 测试阶段
1. **功能测试**:验证所有按钮和交互功能
2. **收起测试**:测试收起/展开功能正常工作
3. **适配测试**:验证不同分辨率下的显示效果
---
## 七、注意事项
1. **组件复用**:相同功能的组件尽量复用,减少冗余
2. **状态管理**:收起状态需要正确保存和恢复
3. **图标反馈**:收起按钮图标应随状态变化
4. **性能优化**:可收起区域使用 `SetActive` 而非销毁重建
5. **命名规范**:统一的命名规则便于维护和查找
---
**版本**: v1.0
**适用**: StrayFog框架UI拼接开发人员

View File

@@ -1,352 +0,0 @@
# StrayFog 框架 UI开发指南
## 一、UI窗口开发
### 1.1 窗口创建模板
```csharp
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/MyWindow/MyWindow.prefab")]
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Dynamic, isIgnoreCloseByESC = false)]
public class MyWindow : AbsHFUIWindow
{
// UI组件
private SFUI_Button BtnClose;
private SFUI_TextMeshProUGUI TxtTitle;
protected override void OnRunAwake()
{
base.OnRunAwake();
// 初始化UI组件引用
BtnClose = FindUICtrlByName<SFUI_Button>("BtnClose");
TxtTitle = FindUICtrlByName<SFUI_TextMeshProUGUI>("TxtTitle");
// 绑定按钮事件OnRunAwake只执行一次
BtnClose.OnAddClickListener += OnBtnClose;
}
protected override void OnOpen(Action _onOpenComplete)
{
base.OnOpen(_onOpenComplete);
// 注册全局事件监听(每次打开都要注册)
HFFunCatalogue.Event.TCEvent.AddListener<HFEvent_DataUpdate>(
enHFCTCEvent.DataUpdate, OnDataUpdate);
// 初始化数据显示
RefreshUI();
}
protected override void OnClose(Action _onCloseComplete)
{
// 取消全局事件监听(每次关闭都要取消)
HFFunCatalogue.Event.TCEvent.RemoveListener<HFEvent_DataUpdate>(
enHFCTCEvent.DataUpdate, OnDataUpdate);
base.OnClose(_onCloseComplete);
}
private void OnBtnClose(GameObject go) => CloseWindow();
private void OnDataUpdate(IHFEventArg<enHFCTCEvent> arg) => RefreshUI();
private void RefreshUI() { /* 更新UI显示 */ }
}
```
### 1.2 窗口生命周期
| 方法 | 调用时机 | 说明 | 推荐操作 |
|-----|---------|------|---------|
| `OnRunAwake` | 窗口创建时调用一次 | 初始化组件引用 | **绑定按钮事件、初始化对象池** |
| `OnRunStart` | OnRunAwake之后调用一次 | 初始化数据 | **配置数据加载** |
| `OnOpen` | 每次打开窗口时调用 | 注册事件、刷新数据 | **注册TC事件、初始化数据显示** |
| `OnClose` | 每次关闭窗口时调用 | 取消事件、清理资源 | **取消TC事件、回收对象池** |
| `OnDestroy` | 窗口销毁时调用 | 释放资源 | **释放非托管资源** |
### 1.3 窗口操作
```csharp
// 打开窗口
HFFunCatalogue.UIManager.OpenWindow<MyWindow>();
// 打开窗口并获取实例
HFFunCatalogue.UIManager.OpenWindow<MyWindow>((win, args) => {
// win: 窗口实例
});
// 关闭窗口
HFFunCatalogue.UIManager.CloseWindow<MyWindow>();
```
---
## 二、事件绑定规范
### 2.1 事件绑定位置
| 事件类型 | 推荐位置 | 原因 | 是否需要 `-=` 防重复 |
|---------|---------|------|-------------------|
| **UI按钮事件** | `OnRunAwake` | 静态稳定,只需注册一次 | ❌ 不需要 |
| **列表拖拽事件** | `OnRunAwake` | 窗口生命周期内持续响应 | ❌ 不需要 |
| **全局TC事件** | `OnOpen`/`OnClose` | 窗口关闭后不应响应 | ✅ 需要 |
| **数据刷新逻辑** | `OnOpen` | 每次打开窗口需刷新 | - |
---
## 三、常用UI组件
### 3.1 SFUI_Button组件
```csharp
SFUI_Button btn = GetComponent<SFUI_Button>();
// 添加事件
btn.OnAddClickListener += OnBtnClick;
btn.OnAddEnterListener += OnBtnEnter;
btn.OnAddExitListener += OnBtnExit;
// 设置状态
btn.SetSelfGray(true); // 灰色不可用
btn.interactable = false; // 不可交互
btn.SetSelected(true); // 选中状态
```
### 3.2 SFUI_TextMeshProUGUI组件
```csharp
SFUI_TextMeshProUGUI txt = GetComponent<SFUI_TextMeshProUGUI>();
txt.text = "Hello World";
txt.color = Color.red;
txt.fontSize = 24;
txt.outlineColor = Color.black;
txt.outlineWidth = 2;
// 动态调整高度
txt.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, txt.preferredHeight);
```
### 3.3 SFUI_Image组件
```csharp
SFUI_Image img = GetComponent<SFUI_Image>();
// 加载Sprite
img.HFSetSprite(enHFSpriteAtlas.ASSETS_GAME_GAMEHFRESOURCE_SPRITEATLAS_ITEM,
"Icon_Player",
enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE);
// 设置透明度
img.SetAlpha(0.5f);
// 设置灰度
img.SetSelfGray(true);
// 清空Sprite
img.HFClearSprite();
```
### 3.4 SFUI_ScrollRect组件列表滚动
SFUI_ScrollRect 专门用于处理多物品的上下滑动列表,**内置对象池机制实现循环列表**,提供高效的列表渲染和滚动管理。
```csharp
SFUI_ScrollRect scroll = GetComponent<SFUI_ScrollRect>();
// 绑定列表数据(核心方法)
scroll.BindEvent(
() => itemList.Count, // 数据数量
(idx) => itemPrefab.gameObject, // 获取模板对象
OnUpdateItem, // 更新回调
(item) => item.gameObject.HFGetOrAddSimulateBehaviour<ItemSlot>() // 获取组件
);
// 刷新列表显示
scroll.ShowView();
// 滚动到指定位置
scroll.ScrollToIndex(0); // 滚动到第N项
scroll.verticalNormalizedPosition = 0; // 滚动到底部1=顶部0=底部)
```
**BindEvent 参数说明**
| 参数 | 类型 | 说明 |
|-----|------|------|
| 1 | `Func<int>` | 返回数据总数 |
| 2 | `Func<int, GameObject>` | 根据索引返回模板对象 |
| 3 | `Action<SFUI_ScrollRectItem>` | 列表项更新回调 |
| 4 | `Func<SFUI_ScrollRectItem, AbsHFUIWindow>` | 获取列表项组件 |
**更新回调示例**
```csharp
private void OnUpdateItem(SFUI_ScrollRectItem _item)
{
ItemSlot slot = _item.simulateBehaviour as ItemSlot;
ItemData data = itemList[_item.dataIdx];
slot.SetData(data, OnItemClick);
}
```
**使用流程**
1.`OnRunAwake` 中调用 `BindEvent` 绑定数据
2.`OnOpen` 或数据更新时调用 `ShowView` 刷新显示
3. 通过 `ScrollToIndex``verticalNormalizedPosition` 控制滚动位置
> **注意**SFUI_ScrollRect 已内置对象池机制,**无需额外使用 HFSimulateBehaviourPool** 实现循环列表。
---
## 四、对象池模式
> **注意****循环滚动列表请使用 `SFUI_ScrollRect.BindEvent`**HFSimulateBehaviourPool 适用于非滚动场景的对象复用。
### 4.1 对象池初始化
```csharp
HFSimulateBehaviourPool<ItemSlot> m_ItemPool = null;
protected override void OnRunAwake()
{
base.OnRunAwake();
SFUI_Button itemPrefab = FindUICtrlByName<SFUI_Button>("ItemPrefab");
SFUI_Behaviour parentContainer = FindUICtrlByName<SFUI_Behaviour>("ParentContainer");
// 创建对象池
m_ItemPool = new HFSimulateBehaviourPool<ItemSlot>(
itemPrefab.gameObject, // 模板对象
parentContainer.gameObject // 父容器
);
}
```
### 4.2 对象池使用(适用于固定数量场景)
```csharp
private void RefreshItems()
{
// 回收所有已使用对象
m_ItemPool.RecycUsingObject();
// 遍历数据创建新对象
foreach (var data in itemDataList)
{
ItemSlot slot = m_ItemPool.GetItem(out bool isNew);
slot.SetData(data, OnItemClick);
}
}
// 适用于固定数量的装备栏、技能栏等场景
private void ShowEquipedCards()
{
m_CardItems.RecycUsingObject();
for (int i = 0; i < 5; i++)
{
var item = m_CardItems.GetItem(out bool isNew);
// 设置数据...
}
}
```
### 4.3 适用场景对比
| 场景 | 推荐方式 | 说明 |
|-----|---------|------|
| **滚动列表** | `SFUI_ScrollRect.BindEvent` | 自动实现循环复用 |
| **固定数量栏** | `HFSimulateBehaviourPool` | 如装备栏、技能栏5个固定位置 |
| **动态弹窗** | `HFSimulateBehaviourPool` | 需要频繁创建销毁的弹窗 |
---
## 五、子组件开发
子组件作为列表项使用,继承 `AbsHFUIWindow`,核心特点:
| 特点 | 说明 |
|-----|------|
| **数据传递** | 通过 `SetData` 方法接收数据 |
| **回调机制** | 通过 `Action<T>` 与父组件通信 |
| **对象池** | 配合 `HFSimulateBehaviourPool<T>` 实现复用 |
---
## 六、UI开发规范
### 6.1 文件放置结构
UI相关文件应按照以下规范组织
**脚本文件**.cs
```
Assets/Game/GameHFScripte/GameFunction/UIWindows/
├── BagWindow/
│ └── BagWindow.cs # 窗口脚本
├── MainWindow/
│ └── MainWindow.cs
└── Common/
└── ItemSlot.cs # 公共子组件脚本
```
**预制体文件**.prefab
```
Assets/Game/GameHFResource/CN/UIWindows/
├── BagWindow/
│ └── BagWindow.prefab # 窗口预制体
├── MainWindow/
│ └── MainWindow.prefab
└── Common/
└── ItemSlot.prefab # 公共子组件预制体
```
**图片资源**按UI名称分类
```
Assets/Game/GameHFResource/CN/SpriteAtlas/
├── BagWindow/ # 背包窗口相关图片
│ ├── Icon_Bag.png
│ └── Btn_Close.png
├── MainWindow/ # 主窗口相关图片
│ └── Btn_Menu.png
└── Common/ # 公共图片
└── Btn_Confirm.png
```
### 6.2 窗口属性配置
每个窗口必须配置以下属性:
```csharp
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE,
"UIWindows/BagWindow/BagWindow.prefab")]
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow,
enHFUIWindowLayer.Dynamic,
isIgnoreCloseByESC = false)]
public class BagWindow : AbsHFUIWindow
{
// ...
}
```
**路径对应关系**
- 属性路径:`UIWindows/BagWindow/BagWindow.prefab`
- 实际路径:`Assets/Game/GameHFResource/CN/UIWindows/BagWindow/BagWindow.prefab`
**属性说明**
| 属性 | 作用 | 必填 |
|-----|------|------|
| `HFAssetBundlePath` | 指定预制体路径,用于资源加载 | ✅ |
| `HFUIWindowLayer` | 指定窗口层级和行为 | ✅ |
| `isIgnoreCloseByESC` | 是否忽略ESC关闭 | ❌ |
### 6.3 性能优化建议
| 优化项 | 说明 | 实现方式 |
|-------|------|---------|
| **对象池复用** | 频繁创建的UI元素使用对象池 | 使用 `HFSimulateBehaviourPool<T>` |
| **图集打包** | 将小图标打包到SpriteAtlas | 在Unity中配置SpriteAtlas |
| **层级优化** | 合理设置Canvas层级 | 使用 `HFUIWindowLayer` 属性 |
| **避免过度绘制** | 减少重叠UI元素 | 合理设计UI布局 |
| **批量操作** | 使用RectTransform批量修改 | 禁用后批量修改再启用 |
| **列表优化** | 使用SFUI_ScrollRect绑定模式 | 自动复用列表项 |
---
**版本**: v1.0
**适用范围**: StrayFog框架项目业务开发人员

View File

@@ -13,7 +13,10 @@
- [事件系统使用指南](03_核心功能/事件系统使用指南.md)
- [资源管理使用指南](03_核心功能/资源管理使用指南.md)
- [相机系统使用指南](03_核心功能/相机系统使用指南.md)
- [UI开发指南](03_核心功能/UI开发指南.md) - 窗口开发、组件使用、事件绑定、对象池、开发规范
#### UI相关
- [UI开发指南](03_核心功能/UI/UI开发指南.md) - 窗口开发、组件使用、事件绑定、对象池、开发规范
- [UI界面拼接设计指南](03_核心功能/UI/UI界面拼接设计指南.md) - 界面模块化设计、布局规划、模块组装
### 04_开发流程
- [开发流程指南](04_开发流程/开发流程指南.md)