更新UI相关指南文档 v1.1

修改内容:
1. UI事件绑定指南:新增事件绑定位置规范,强调防重复注册保护,新增SFUI_ScrollRect绑定模式
2. UI窗口开发指南:更新窗口创建流程示例,添加子组件开发示例
3. UI组件使用指南:添加防重复注册保护,新增列表绑定模式和子组件开发规范
This commit is contained in:
Shiliang
2026-05-22 14:40:44 +08:00
parent 75687450ad
commit 094ae2eedb
3 changed files with 416 additions and 197 deletions

View File

@@ -1,90 +1,146 @@
# StrayFog 框架 UI事件绑定指南 # StrayFog 框架 UI事件绑定指南
## 一、事件绑定方式 ## 一、事件绑定位置规范
### 1.1 代码绑定(使用框架封装组件) ### 1.1 事件绑定位置总览
| 事件类型 | 推荐位置 | 原因 |
|---------|---------|------|
| **UI按钮事件** | `OnRunAwake` | 静态稳定,只需注册一次 |
| **列表拖拽事件** | `OnRunAwake` | 窗口生命周期内持续响应 |
| **全局CTC事件** | `OnOpen`/`OnClose` | 窗口关闭后不应响应 |
| **数据刷新逻辑** | `OnOpen` | 每次打开窗口需刷新 |
### 1.2 推荐绑定模式(防重复注册保护)
```csharp ```csharp
public class LoginWindow : AbsHFUIWindow public class BagWindow : AbsHFUIWindow
{ {
private SFUI_Button BtnLogin; private SFUI_Button BtnClose;
private SFUI_ScrollRect BagListView;
protected override void OnRunAwake() protected override void OnRunAwake()
{ {
base.OnRunAwake(); base.OnRunAwake();
// OnRunAwake: 初始化组件引用和按钮事件绑定(仅调用一次) BtnClose = FindUICtrlByName<SFUI_Button>("BtnClose");
BtnLogin = FindUICtrlByName<SFUI_Button>("BtnLogin"); BagListView = FindUICtrlByName<SFUI_ScrollRect>("BagListView");
if (BtnLogin != null) // ✅ 按钮事件放在 OnRunAwake先取消再注册防止重复
{ BtnClose.OnAddClickListener -= OnBtnClose;
BtnLogin.OnAddClickListener += OnBtnLoginClick; BtnClose.OnAddClickListener += OnBtnClose;
BtnLogin.OnAddEnterListener += OnBtnLoginEnter;
BtnLogin.OnAddExitListener += OnBtnLoginExit; // ✅ 列表事件也放在 OnRunAwake
} BagListView.OnAddBeginDragListener -= OnBeginDrag;
BagListView.OnAddBeginDragListener += OnBeginDrag;
} }
protected override void OnOpen(Action _onOpenComplete) protected override void OnOpen(Action _onOpenComplete)
{ {
base.OnOpen(_onOpenComplete); base.OnOpen(_onOpenComplete);
// OnOpen: 注册CTC事件监听每次打开调用 // ✅ 全局CTC事件放在 OnOpen
HFFunCatalogue.Event.CTCEvent.AddListener<HFEvent_CTC_LoginResult>( HFFunCatalogue.Event.TCEvent.AddListener<HFEvent_BagItemUpdate>(
enHFCTCEvent.LoginResult, OnLoginResult); enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
} }
protected override void OnClose(Action _onCloseComplete) protected override void OnClose(Action _onCloseComplete)
{ {
// OnClose: 移除事件监听(每次关闭调用) // ✅ 全局CTC事件在 OnClose 取消
if (BtnLogin != null) HFFunCatalogue.Event.TCEvent.RemoveListener<HFEvent_BagItemUpdate>(
{ enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
BtnLogin.OnAddClickListener -= OnBtnLoginClick;
BtnLogin.OnAddEnterListener -= OnBtnLoginEnter;
BtnLogin.OnAddExitListener -= OnBtnLoginExit;
}
HFFunCatalogue.Event.CTCEvent.RemoveListener<HFEvent_CTC_LoginResult>(
enHFCTCEvent.LoginResult, OnLoginResult);
base.OnClose(_onCloseComplete); base.OnClose(_onCloseComplete);
} }
void OnBtnLoginClick(GameObject go) private void OnBtnClose(GameObject go) { /* 按钮点击处理 */ }
{ private void OnBeginDrag(GameObject go) { /* 拖拽处理 */ }
// 处理登录逻辑 - 使用框架标准调用方式 private void OnBagItemUpdate(IHFEventArg<enHFCTCEvent> arg) { /* 数据更新处理 */ }
HFEvent_CTC_Login evt = HFFunCatalogue.New<HFEvent_CTC_Login>();
evt.account = "player_account";
evt.password = "encrypted_password";
evt.Dispatch();
}
void OnBtnLoginEnter(GameObject go)
{
// 鼠标进入
}
void OnBtnLoginExit(GameObject go)
{
// 鼠标退出
}
void OnLoginResult(HFEventArgBase arg)
{
// 处理登录结果
}
} }
``` ```
### 1.2 框架封装UI组件列表 ### 1.3 防重复注册原理
| 组件名 | 基类 | 说明 | ```csharp
|-------|------|------| // 先取消注册,再添加注册
| `SFUI_Button` | `AbsSFUI_Button : Button` | 按钮组件 | BtnLogin.OnAddClickListener -= OnBtnLoginClick; // 防止重复注册
| `SFUI_Text` | `AbsSFUI_Text : Text` | 文本组件 | BtnLogin.OnAddClickListener += OnBtnLoginClick; // 安全注册
| `SFUI_Image` | `AbsSFUI_Image : Image` | 图片组件 | ```
| `SFUI_Toggle` | `AbsSFUI_Toggle : Toggle` | 开关组件 |
| `SFUI_ScrollRect` | `AbsSFUI_ScrollRect : ScrollRect` | 滚动区域 |
| `SFUI_InputField` | `AbsSFUI_InputField : InputField` | 输入框 |
### 1.3 SFUI_Button事件委托 **作用**:即使`OnRunAwake`被多次调用(如对象池复用),也不会导致事件重复触发。
---
## 二、SFUI_ScrollRect 绑定模式
### 2.1 列表绑定(推荐)
```csharp
protected override void OnRunAwake()
{
base.OnRunAwake();
var itemPrefab = FindUICtrlByName<SFUI_Behaviour>("Item");
BagListView = FindUICtrlByName<SFUI_ScrollRect>("BagListView");
BagListView.BindEvent(
() => { return m_items.Count; }, // 数据源数量
(idx) => { return itemPrefab.gameObject; }, // 实例化模板
OnUpdateItem, // 更新回调
(item) => { // 组件获取
return item.gameObject.HFGetOrAddSimulateBehaviour<BagItemSlot>();
}
);
}
private void OnUpdateItem(SFUI_ScrollRectItem item)
{
var bagItem = item.simulateBehaviour as BagItemSlot;
bagItem.SetData(m_items[item.dataIdx], m_select, item.dataIdx, OnSelect);
}
```
### 2.2 列表刷新
```csharp
// 刷新整个列表
BagListView.ShowView();
// 刷新指定项
BagListView.RefreshView(null);
// 滚动到指定位置
BagListView.ScrollToIndex(0);
```
---
## 三、事件系统分类
### 3.1 TCEvent客户端事件
```csharp
// 注册监听(在 OnOpen 中)
HFFunCatalogue.Event.TCEvent.AddListener<HFEvent_BagItemUpdate>(
enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
// 取消监听(在 OnClose 中)
HFFunCatalogue.Event.TCEvent.RemoveListener<HFEvent_BagItemUpdate>(
enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
```
### 3.2 STCEvent服务器事件
```csharp
// 在 Manager 层注册UI窗口不直接监听
HFFunCatalogue.Event.STCEvent.AddListener<HFEvent_STC_GetBagS2C>(
enHFSTCEvent.GetBag, OnPushBagItem);
```
> **注意**UI窗口中不直接监听STCEvent应在Logic层Manager中监听然后通过TCEvent通知UI。
---
## 四、按钮事件委托
### 4.1 SFUI_Button 事件列表
| 事件 | 委托签名 | 说明 | | 事件 | 委托签名 | 说明 |
|-----|---------|------| |-----|---------|------|
@@ -92,51 +148,10 @@ public class LoginWindow : AbsHFUIWindow
| `OnAddEnterListener` | `Enter(GameObject go)` | 鼠标进入 | | `OnAddEnterListener` | `Enter(GameObject go)` | 鼠标进入 |
| `OnAddExitListener` | `Exit(GameObject go)` | 鼠标退出 | | `OnAddExitListener` | `Exit(GameObject go)` | 鼠标退出 |
| `OnAddPointerUpListener` | `PointerUp(GameObject go)` | 指针抬起 | | `OnAddPointerUpListener` | `PointerUp(GameObject go)` | 指针抬起 |
| `OnAddBeginDragListener` | `BeginDrag(GameObject go)` | 开始拖拽 |
| `OnAddEndDragListener` | `EndDrag(GameObject go)` | 结束拖拽 |
--- ---
## 二、事件系统分类 **版本**: v1.1
### 2.1 CTCEvent客户端内部事件
```csharp
// 注册监听
HFFunCatalogue.Event.CTCEvent.AddListener<HFEvent_CTC_CardUpdate>(
enHFCTCEvent.CardUpdate, OnCardUpdate);
// 触发事件
HFEvent_CTC_CardUpdate evt = HFFunCatalogue.New<HFEvent_CTC_CardUpdate>();
evt.cardId = 123;
HFFunCatalogue.Event.CTCEvent.Dispatch(evt);
```
### 2.2 STCEvent服务器事件
```csharp
// 在Manager中注册
HFFunCatalogue.Event.STCEvent.AddListener<HFEvent_STC_PlayerInfo>(
enHFSTCEvent.PlayerInfo, OnPlayerInfo);
```
> **注意**UI窗口中不监听STCEvent应在Logic层Manager中监听。
---
## 三、事件参数回收
### 3.1 使用对象池
```csharp
// 获取事件参数(从对象池获取)
HFEvent_CTC_PlayerLevelUp evt = HFFunCatalogue.New<HFEvent_CTC_PlayerLevelUp>();
evt.playerId = 1;
evt.newLevel = 10;
// 触发事件(事件系统会自动回收)
HFFunCatalogue.Event.CTCEvent.Dispatch(evt);
```
---
**版本**: v1.0
**适用范围**: GiftGameX项目业务开发人员 **适用范围**: GiftGameX项目业务开发人员

View File

@@ -5,52 +5,67 @@
### 1.1 窗口创建流程 ### 1.1 窗口创建流程
```csharp ```csharp
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/Login/LoginWindow.prefab")] [HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/Bag/BagWindow.prefab")]
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Dynamic, isIgnoreCloseByESC = false)] [HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Fixed, isIgnoreCloseByESC = false)]
public class LoginWindow : AbsHFUIWindow public class BagWindow : AbsHFUIWindow
{ {
// ========== UI组件 ========== // ========== UI组件 ==========
private SFUI_Button BtnLogin; private SFUI_Button BtnClose;
private SFUI_InputField InputName; private SFUI_ScrollRect BagListView;
private SFUI_InputField InputPassword; private BagTips tips;
private SFUI_TextMeshProUGUI TxtTitle;
// ========== 数据 ==========
private List<ItemInfo> m_items = new List<ItemInfo>();
private ItemInfo m_select;
protected override void OnRunAwake() protected override void OnRunAwake()
{ {
base.OnRunAwake(); base.OnRunAwake();
// 初始化UI组件引用(变量名与组件名保持一致) // 初始化UI组件引用
BtnLogin = FindUICtrlByName<SFUI_Button>("BtnLogin"); BtnClose = FindUICtrlByName<SFUI_Button>("BtnClose");
InputName = FindUICtrlByName<SFUI_InputField>("InputName"); BagListView = FindUICtrlByName<SFUI_ScrollRect>("BagListView");
InputPassword = FindUICtrlByName<SFUI_InputField>("InputPassword"); tips = BindUI<BagTips, SFUI_Image>("BagTips");
TxtTitle = FindUICtrlByName<SFUI_TextMeshProUGUI>("TxtTitle");
// 绑定按钮事件 // 按钮事件绑定(带防重复注册保护)
if (BtnLogin != null) BtnClose.OnAddClickListener -= OnBtnClose;
{ BtnClose.OnAddClickListener += OnBtnClose;
BtnLogin.OnAddClickListener += OnBtnLoginClick;
} // ✅ 列表绑定
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) protected override void OnOpen(Action _onOpenComplete)
{ {
base.OnOpen(_onOpenComplete); base.OnOpen(_onOpenComplete);
// 注册事件监听 // ✅ 注册全局事件监听
HFFunCatalogue.Event.TCEvent.AddListener<HFEvent_BagItemUpdate>(
enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
// ✅ 初始化数据
RefreshBagItems();
} }
protected override void OnClose(Action _onCloseComplete) protected override void OnClose(Action _onCloseComplete)
{ {
// 取消事件监听 // ✅ 取消全局事件监听
if (BtnLogin != null) HFFunCatalogue.Event.TCEvent.RemoveListener<HFEvent_BagItemUpdate>(
{ enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
BtnLogin.OnAddClickListener -= OnBtnLoginClick;
} // ✅ 清理资源
tips.Clear();
base.OnClose(_onCloseComplete); base.OnClose(_onCloseComplete);
} }
private void OnBtnLoginClick(GameObject go) private void OnBtnClose(GameObject go) => CloseWindow();
{ private void OnUpdateItem(SFUI_ScrollRectItem item) { /* 更新列表项 */ }
// 处理登录逻辑 private void RefreshBagItems() { /* 刷新背包数据 */ }
}
} }
``` ```
@@ -58,18 +73,16 @@ public class LoginWindow : AbsHFUIWindow
```csharp ```csharp
// 方式1直接打开无回调 // 方式1直接打开无回调
HFFunCatalogue.UIManager.OpenWindow<LoginWindow>(); HFFunCatalogue.UIManager.OpenWindow<BagWindow>();
// 方式2打开并获取窗口实例推荐 // 方式2打开并获取窗口实例推荐
HFFunCatalogue.UIManager.OpenWindow<LoginWindow>((win, args) => { HFFunCatalogue.UIManager.OpenWindow<BagWindow>((win, args) => {
// win: 打开的窗口实例
// args: 传入的额外参数
Debug.Log("窗口打开完成"); Debug.Log("窗口打开完成");
}); });
// 方式3带额外参数打开 // 方式3带额外参数打开
object[] extraArgs = new object[] { "param1", 123 }; object[] extraArgs = new object[] { "param1", 123 };
HFFunCatalogue.UIManager.OpenWindow<LoginWindow>((win, args) => { HFFunCatalogue.UIManager.OpenWindow<BagWindow>((win, args) => {
// 使用窗口实例 // 使用窗口实例
}, extraArgs); }, extraArgs);
``` ```
@@ -80,12 +93,32 @@ HFFunCatalogue.UIManager.OpenWindow<LoginWindow>((win, args) => {
### 2.1 生命周期方法 ### 2.1 生命周期方法
| 方法 | 调用时机 | 说明 | | 方法 | 调用时机 | 说明 | 推荐操作 |
|-----|---------|------| |-----|---------|------|---------|
| `OnRunAwake` | 窗口创建时调用一次 | 初始化组件引用 | | `OnRunAwake` | 窗口创建时调用一次 | 初始化组件引用 | **绑定按钮事件、列表初始化** |
| `OnOpen` | 每次打开窗口时调用 | 注册事件、刷新数据 | | `OnOpen` | 每次打开窗口时调用 | 注册事件、刷新数据 | **注册全局TC事件、初始化数据** |
| `OnClose` | 每次关闭窗口时调用 | 取消事件、清理资源 | | `OnClose` | 每次关闭窗口时调用 | 取消事件、清理资源 | **取消全局TC事件、清理UI状态** |
| `OnDestroy` | 窗口销毁时调用 | 释放资源 | | `OnDestroy` | 窗口销毁时调用 | 释放资源 | **释放非托管资源** |
### 2.2 生命周期流程图
```
窗口创建
OnRunAwake() ──→ 初始化组件、绑定按钮事件
窗口打开(可多次)
OnOpen() ──→ 注册TC事件、刷新数据
窗口关闭(可多次)
OnClose() ──→ 取消TC事件、清理资源
窗口销毁
OnDestroy() ──→ 释放资源
```
--- ---
@@ -100,7 +133,96 @@ HFFunCatalogue.UIManager.OpenWindow<LoginWindow>((win, args) => {
| `isNeedMask` | 是否需要遮罩 | true | | `isNeedMask` | 是否需要遮罩 | true |
| `maskType` | 遮罩类型 | 半透明 | | `maskType` | 遮罩类型 | 半透明 |
### 3.2 层叠配置
```csharp
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Fixed, isIgnoreCloseByESC = false)]
// ↑ Canvas层级 ↑ 窗口层级
```
--- ---
**版本**: v1.0 ## 四、子组件开发
### 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项目业务开发人员 **适用范围**: GiftGameX项目业务开发人员

View File

@@ -7,37 +7,31 @@
```csharp ```csharp
SFUI_Button btn = GetComponent<SFUI_Button>(); SFUI_Button btn = GetComponent<SFUI_Button>();
// 添加点击事件 // 添加点击事件(带防重复注册保护)
btn.OnAddClickListener -= OnBtnClick;
btn.OnAddClickListener += OnBtnClick; btn.OnAddClickListener += OnBtnClick;
// 添加鼠标进入/退出事件 // 添加鼠标进入/退出事件
btn.OnAddEnterListener -= OnBtnEnter;
btn.OnAddEnterListener += OnBtnEnter; btn.OnAddEnterListener += OnBtnEnter;
btn.OnAddExitListener -= OnBtnExit;
btn.OnAddExitListener += OnBtnExit; btn.OnAddExitListener += OnBtnExit;
// 设置按钮状态 // 设置按钮状态
btn.SetSelfGray(true); // 设置灰色不可用 btn.SetSelfGray(true); // 设置灰色不可用
btn.interactable = false; // 设置不可交互 btn.interactable = false; // 设置不可交互
btn.SetSelected(true); // 设置选中状态
void OnBtnClick(GameObject go) void OnBtnClick(GameObject go) { /* 处理点击 */ }
{ void OnBtnEnter(GameObject go) { /* 鼠标进入 */ }
// 处理点击 void OnBtnExit(GameObject go) { /* 鼠标退出 */ }
}
void OnBtnEnter(GameObject go)
{
// 鼠标进入
}
void OnBtnExit(GameObject go)
{
// 鼠标退出
}
``` ```
### 1.2 SFUI_Text组件 ### 1.2 SFUI_TextMeshProUGUI组件
```csharp ```csharp
SFUI_Text txt = GetComponent<SFUI_Text>(); SFUI_TextMeshProUGUI txt = GetComponent<SFUI_TextMeshProUGUI>();
// 设置文本 // 设置文本
txt.text = "Hello World"; txt.text = "Hello World";
@@ -58,16 +52,20 @@ txt.outlineWidth = 2;
```csharp ```csharp
SFUI_Image img = GetComponent<SFUI_Image>(); SFUI_Image img = GetComponent<SFUI_Image>();
// 加载Sprite // 加载Sprite(使用框架封装方法)
HFFunCatalogue.Sprite.LoadSprite("Icon_Player", sprite => { img.HFSetItemIcon("Icon_Player");
img.sprite = sprite;
}); // 加载远程图片
img.HFSetUrlSprite("https://example.com/icon.png");
// 设置透明度 // 设置透明度
img.SetAlpha(0.5f); img.SetAlpha(0.5f);
// 设置灰度 // 设置灰度
img.SetSelfGray(true); img.SetSelfGray(true);
// 清空Sprite
img.HFClearSprite();
``` ```
### 1.4 SFUI_Toggle组件 ### 1.4 SFUI_Toggle组件
@@ -76,6 +74,7 @@ img.SetSelfGray(true);
SFUI_Toggle toggle = GetComponent<SFUI_Toggle>(); SFUI_Toggle toggle = GetComponent<SFUI_Toggle>();
// 添加状态改变事件 // 添加状态改变事件
toggle.onValueChanged.RemoveListener(OnToggleValueChanged);
toggle.onValueChanged.AddListener(OnToggleValueChanged); toggle.onValueChanged.AddListener(OnToggleValueChanged);
void OnToggleValueChanged(bool isOn) void OnToggleValueChanged(bool isOn)
@@ -84,21 +83,38 @@ void OnToggleValueChanged(bool isOn)
} }
``` ```
### 1.5 SFUI_ScrollRect组件 ### 1.5 SFUI_ScrollRect组件(列表绑定模式)
```csharp ```csharp
SFUI_ScrollRect scroll = GetComponent<SFUI_ScrollRect>(); SFUI_ScrollRect scroll = GetComponent<SFUI_ScrollRect>();
List<ItemInfo> m_items = new List<ItemInfo>();
// 设置滚动位置 // ✅ 列表绑定(推荐方式)
scroll.verticalNormalizedPosition = 1f; scroll.BindEvent(
() => { return m_items.Count; }, // 数据源数量
// 添加滚动事件 (idx) => { return itemPrefab.gameObject; }, // 实例化模板
scroll.onValueChanged.AddListener(OnScrollValueChanged); OnUpdateItem, // 更新回调
(item) => { // 组件获取
void OnScrollValueChanged(Vector2 value) return item.gameObject.HFGetOrAddSimulateBehaviour<BagItemSlot>();
{
// 处理滚动
} }
);
// 刷新列表
scroll.ShowView(); // 显示视图
scroll.RefreshView(null); // 刷新当前视图
scroll.ScrollToIndex(0); // 滚动到指定索引
// 添加拖拽事件
scroll.OnAddBeginDragListener -= OnBeginDrag;
scroll.OnAddBeginDragListener += OnBeginDrag;
void OnUpdateItem(SFUI_ScrollRectItem item)
{
var slot = item.simulateBehaviour as BagItemSlot;
slot.SetData(m_items[item.dataIdx]);
}
void OnBeginDrag(GameObject go) { /* 处理拖拽开始 */ }
``` ```
--- ---
@@ -111,23 +127,18 @@ void OnScrollValueChanged(Vector2 value)
| 组件类型 | 示例 | | 组件类型 | 示例 |
|---------|-----| |---------|-----|
| SFUI_Button | BtnLogin | | SFUI_Button | BtnLogin, BtnClose |
| SFUI_Text | TxtTitle | | SFUI_TextMeshProUGUI | TxtTitle, TxtNum |
| SFUI_Image | ImgAvatar | | SFUI_Image | ImgIcon, ImgKuang |
| SFUI_Toggle | ToggleSelect | | SFUI_Toggle | ToggleSelect |
| SFUI_ScrollRect | ScrollContent | | SFUI_ScrollRect | BagListView, ScrollContent |
| SFUI_InputField | InputName | | SFUI_InputField | InputName, InputPassword |
| SFUI_GridLayoutGroup | GridItemContainer |
**命名约定** **命名约定**
- 变量名 = 组件名(保持完全一致) - 变量名 = 组件名(保持完全一致)
- 首字母大写,采用 PascalCase 命名风格 - 首字母大写,采用 PascalCase 命名风格
- 前缀说明Btn按钮、Txt文本、Img图片、Toggle开关、Scroll滚动、Input输入框、Grid网格
**使用示例**
```csharp
BtnLogin = FindUICtrlByName<SFUI_Button>("BtnLogin");
TxtTitle = FindUICtrlByName<SFUI_Text>("TxtTitle");
ImgAvatar = FindUICtrlByName<SFUI_Image>("ImgAvatar");
```
### 2.2 层级结构 ### 2.2 层级结构
@@ -135,10 +146,10 @@ ImgAvatar = FindUICtrlByName<SFUI_Image>("ImgAvatar");
WindowRoot/ WindowRoot/
├── bg/ # 背景层 ├── bg/ # 背景层
├── content/ # 内容层 ├── content/ # 内容层
│ ├── header/ # 头部 │ ├── header/ # 头部(标签页、标题)
│ ├── body/ # 主体 │ ├── body/ # 主体(列表、内容区)
│ └── footer/ # 底部 │ └── footer/ # 底部(操作按钮)
└── top/ # 顶层(弹窗、提示 └── top/ # 顶层(弹窗、提示、遮罩
``` ```
--- ---
@@ -147,14 +158,16 @@ WindowRoot/
| 组件名 | 基类 | 扩展功能 | | 组件名 | 基类 | 扩展功能 |
|-------|------|---------| |-------|------|---------|
| `SFUI_Button` | Button | 灰色状态、多事件委托 | | `SFUI_Button` | Button | 灰色状态、多事件委托、选中状态 |
| `SFUI_Text` | Text | 描边、阴影扩展 | | `SFUI_Text` | Text | 描边、阴影扩展 |
| `SFUI_Image` | Image | 灰度、透明度快捷设置 | | `SFUI_TextMeshProUGUI` | TextMeshProUGUI | 继承原生功能 |
| `SFUI_Image` | Image | 灰度、透明度快捷设置、Sprite加载 |
| `SFUI_Toggle` | Toggle | 状态改变事件 | | `SFUI_Toggle` | Toggle | 状态改变事件 |
| `SFUI_ScrollRect` | ScrollRect | 滚动优化 | | `SFUI_ScrollRect` | ScrollRect | **列表绑定模式、滚动优化** |
| `SFUI_InputField` | InputField | 输入限制 | | `SFUI_InputField` | InputField | 输入限制 |
| `SFUI_Slider` | Slider | 数值范围限制 | | `SFUI_Slider` | Slider | 数值范围限制 |
| `SFUI_Dropdown` | Dropdown | 选项管理 | | `SFUI_Dropdown` | Dropdown | 选项管理 |
| `SFUI_GridLayoutGroup` | GridLayoutGroup | 网格布局 |
--- ---
@@ -162,13 +175,82 @@ WindowRoot/
### 4.1 优化建议 ### 4.1 优化建议
- **对象池复用**频繁创建的UI元素使用对象池 | 优化项 | 说明 | 实现方式 |
- **图集打包**将小图标打包到SpriteAtlas |-------|------|---------|
- **层级优化**合理设置Canvas层级 | **对象池复用** | 频繁创建的UI元素使用对象池 | 使用 `HFClassEntityManager` |
- **避免过度绘制**减少重叠UI元素 | **图集打包** | 将小图标打包到SpriteAtlas | 在Unity中配置SpriteAtlas |
- **批量操作**使用RectTransform批量修改 | **层级优化** | 合理设置Canvas层级 | 使用 `HFUIWindowLayer` 属性 |
| **避免过度绘制** | 减少重叠UI元素 | 合理设计UI布局 |
| **批量操作** | 使用RectTransform批量修改 | 禁用后批量修改再启用 |
| **列表优化** | 使用SFUI_ScrollRect绑定模式 | 自动复用列表项 |
### 4.2 列表性能优化示例
```csharp
// ✅ 使用SFUI_ScrollRect绑定模式自动复用
BagListView.BindEvent(
() => { return m_items.Count; },
(idx) => { return itemPrefab.gameObject; },
OnUpdateItem,
(item) => { return item.gameObject.HFGetOrAddSimulateBehaviour<BagItemSlot>(); }
);
// ✅ 数据变化时只刷新必要项
private void OnBagItemUpdate(IHFEventArg<enHFCTCEvent> arg)
{
// 只在数据实际变化时刷新
if (HasDataChanged())
{
BagListView.ShowView();
}
}
```
--- ---
**版本**: v1.0 ## 五、子组件开发规范
### 5.1 子组件模板
```csharp
public class CustomSlot : AbsHFUIWindow
{
// UI组件
private SFUI_Button Btn_Item;
private SFUI_Image Img_Icon;
// 数据和回调
private Action<ItemInfo> onSelect;
private ItemInfo item;
protected override void OnRunAwake()
{
base.OnRunAwake();
Btn_Item = FindUICtrlByName<SFUI_Button>("Btn_Item");
Img_Icon = FindUICtrlByName<SFUI_Image>("Img_Icon");
// 事件绑定(带防重复保护)
Btn_Item.OnAddClickListener -= OnClick;
Btn_Item.OnAddClickListener += OnClick;
}
public void SetData(ItemInfo item, Action<ItemInfo> onSelect)
{
this.item = item;
this.onSelect = onSelect;
// 更新UI
Img_Icon.HFSetItemIcon(item.ItemConfig.Resource);
}
private void OnClick(GameObject go)
{
onSelect?.Invoke(item);
}
}
```
---
**版本**: v1.1
**适用范围**: GiftGameX项目业务开发人员 **适用范围**: GiftGameX项目业务开发人员