Files
UnityAI/03_核心功能/UI窗口开发指南.md
Shiliang 094ae2eedb 更新UI相关指南文档 v1.1
修改内容:
1. UI事件绑定指南:新增事件绑定位置规范,强调防重复注册保护,新增SFUI_ScrollRect绑定模式
2. UI窗口开发指南:更新窗口创建流程示例,添加子组件开发示例
3. UI组件使用指南:添加防重复注册保护,新增列表绑定模式和子组件开发规范
2026-05-22 14:40:44 +08:00

228 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# StrayFog 框架 UI窗口开发指南
## 一、UI窗口基础
### 1.1 窗口创建流程
```csharp
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/Bag/BagWindow.prefab")]
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Fixed, isIgnoreCloseByESC = false)]
public class BagWindow : AbsHFUIWindow
{
// ========== UI组件 ==========
private SFUI_Button BtnClose;
private SFUI_ScrollRect BagListView;
private BagTips tips;
// ========== 数据 ==========
private List<ItemInfo> m_items = new List<ItemInfo>();
private ItemInfo m_select;
protected override void OnRunAwake()
{
base.OnRunAwake();
// ✅ 初始化UI组件引用
BtnClose = FindUICtrlByName<SFUI_Button>("BtnClose");
BagListView = FindUICtrlByName<SFUI_ScrollRect>("BagListView");
tips = BindUI<BagTips, SFUI_Image>("BagTips");
// ✅ 按钮事件绑定(带防重复注册保护)
BtnClose.OnAddClickListener -= OnBtnClose;
BtnClose.OnAddClickListener += OnBtnClose;
// ✅ 列表绑定
var itemPrefab = FindUICtrlByName<SFUI_Behaviour>("Item");
BagListView.BindEvent(
() => { return m_items.Count; },
(idx) => { return itemPrefab.gameObject; },
OnUpdateItem,
(item) => { return item.gameObject.HFGetOrAddSimulateBehaviour<BagItemSlot>(); }
);
}
protected override void OnOpen(Action _onOpenComplete)
{
base.OnOpen(_onOpenComplete);
// ✅ 注册全局事件监听
HFFunCatalogue.Event.TCEvent.AddListener<HFEvent_BagItemUpdate>(
enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
// ✅ 初始化数据
RefreshBagItems();
}
protected override void OnClose(Action _onCloseComplete)
{
// ✅ 取消全局事件监听
HFFunCatalogue.Event.TCEvent.RemoveListener<HFEvent_BagItemUpdate>(
enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
// ✅ 清理资源
tips.Clear();
base.OnClose(_onCloseComplete);
}
private void OnBtnClose(GameObject go) => CloseWindow();
private void OnUpdateItem(SFUI_ScrollRectItem item) { /* 更新列表项 */ }
private void RefreshBagItems() { /* 刷新背包数据 */ }
}
```
### 1.2 窗口打开方式
```csharp
// 方式1直接打开无回调
HFFunCatalogue.UIManager.OpenWindow<BagWindow>();
// 方式2打开并获取窗口实例推荐
HFFunCatalogue.UIManager.OpenWindow<BagWindow>((win, args) => {
Debug.Log("窗口打开完成");
});
// 方式3带额外参数打开
object[] extraArgs = new object[] { "param1", 123 };
HFFunCatalogue.UIManager.OpenWindow<BagWindow>((win, args) => {
// 使用窗口实例
}, extraArgs);
```
---
## 二、窗口生命周期
### 2.1 生命周期方法
| 方法 | 调用时机 | 说明 | 推荐操作 |
|-----|---------|------|---------|
| `OnRunAwake` | 窗口创建时调用一次 | 初始化组件引用 | **绑定按钮事件、列表初始化** |
| `OnOpen` | 每次打开窗口时调用 | 注册事件、刷新数据 | **注册全局TC事件、初始化数据** |
| `OnClose` | 每次关闭窗口时调用 | 取消事件、清理资源 | **取消全局TC事件、清理UI状态** |
| `OnDestroy` | 窗口销毁时调用 | 释放资源 | **释放非托管资源** |
### 2.2 生命周期流程图
```
窗口创建
OnRunAwake() ──→ 初始化组件、绑定按钮事件
窗口打开(可多次)
OnOpen() ──→ 注册TC事件、刷新数据
窗口关闭(可多次)
OnClose() ──→ 取消TC事件、清理资源
窗口销毁
OnDestroy() ──→ 释放资源
```
---
## 三、窗口配置属性
### 3.1 常用属性
| 属性 | 说明 | 默认值 |
|-----|------|-------|
| `isIgnoreCloseByESC` | 是否忽略ESC关闭 | false |
| `isCloseOtherWindow` | 是否关闭其他窗口 | false |
| `isNeedMask` | 是否需要遮罩 | true |
| `maskType` | 遮罩类型 | 半透明 |
### 3.2 层叠配置
```csharp
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Fixed, isIgnoreCloseByESC = false)]
// ↑ Canvas层级 ↑ 窗口层级
```
---
## 四、子组件开发
### 4.1 物品槽组件示例
```csharp
public class BagItemSlot : AbsHFUIWindow
{
private SFUI_Button Btn_Item;
private SFUI_Image Img_Icon;
private SFUI_TextMeshProUGUI Txt_Num;
private Action<ItemInfo, int, Vector3> selectCallback;
private ItemInfo item;
private int m_index;
protected override void OnRunAwake()
{
base.OnRunAwake();
Btn_Item = FindUICtrlByName<SFUI_Button>("Btn_Item");
Img_Icon = FindUICtrlByName<SFUI_Image>("Img_Icon");
Txt_Num = FindUICtrlByName<SFUI_TextMeshProUGUI>("Txt_Num");
Btn_Item.OnAddClickListener -= OnClick;
Btn_Item.OnAddClickListener += OnClick;
}
public void SetData(ItemInfo item, ItemInfo nowSelect, int index, Action<ItemInfo, int, Vector3> onSelect)
{
this.item = item;
this.m_index = index;
this.selectCallback = onSelect;
Img_Icon.HFSetItemIcon(item.ItemConfig.Resource);
Txt_Num.text = item.Info.count.ToString();
}
private void OnClick(GameObject go)
{
selectCallback?.Invoke(item, m_index, go.transform.position);
}
}
```
### 4.2 提示框组件示例
```csharp
public class BagTips : AbsHFUIWindow
{
private SFUI_Image Img_ItemIcon;
private SFUI_TextMeshProUGUI Txt_ItemName;
private SFUI_TextMeshProUGUI Txt_ItemDesc;
public ItemInfo Info { get; private set; }
protected override void OnRunAwake()
{
base.OnRunAwake();
Img_ItemIcon = FindUICtrlByName<SFUI_Image>("Img_ItemIcon");
Txt_ItemName = FindUICtrlByName<SFUI_TextMeshProUGUI>("Txt_ItemName");
Txt_ItemDesc = FindUICtrlByName<SFUI_TextMeshProUGUI>("Txt_ItemDesc");
}
public void SetData(ItemInfo item)
{
Info = item;
Img_ItemIcon.HFSetItemIcon(item.ItemConfig.Resource);
Txt_ItemName.text = item.ItemConfig.NameCN;
Txt_ItemDesc.text = item.ItemConfig.DesLanguageCN;
}
public void Clear()
{
Info = null;
Img_ItemIcon.HFClearSprite();
Txt_ItemName.text = string.Empty;
Txt_ItemDesc.text = string.Empty;
}
}
```
---
**版本**: v1.1
**适用范围**: GiftGameX项目业务开发人员