更新UI相关指南文档 v1.1
修改内容: 1. UI事件绑定指南:新增事件绑定位置规范,强调防重复注册保护,新增SFUI_ScrollRect绑定模式 2. UI窗口开发指南:更新窗口创建流程示例,添加子组件开发示例 3. UI组件使用指南:添加防重复注册保护,新增列表绑定模式和子组件开发规范
This commit is contained in:
@@ -1,90 +1,146 @@
|
||||
# StrayFog 框架 UI事件绑定指南
|
||||
|
||||
## 一、事件绑定方式
|
||||
## 一、事件绑定位置规范
|
||||
|
||||
### 1.1 代码绑定(使用框架封装组件)
|
||||
### 1.1 事件绑定位置总览
|
||||
|
||||
| 事件类型 | 推荐位置 | 原因 |
|
||||
|---------|---------|------|
|
||||
| **UI按钮事件** | `OnRunAwake` | 静态稳定,只需注册一次 |
|
||||
| **列表拖拽事件** | `OnRunAwake` | 窗口生命周期内持续响应 |
|
||||
| **全局CTC事件** | `OnOpen`/`OnClose` | 窗口关闭后不应响应 |
|
||||
| **数据刷新逻辑** | `OnOpen` | 每次打开窗口需刷新 |
|
||||
|
||||
### 1.2 推荐绑定模式(防重复注册保护)
|
||||
|
||||
```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()
|
||||
{
|
||||
base.OnRunAwake();
|
||||
// OnRunAwake: 初始化组件引用和按钮事件绑定(仅调用一次)
|
||||
BtnLogin = FindUICtrlByName<SFUI_Button>("BtnLogin");
|
||||
|
||||
if (BtnLogin != null)
|
||||
{
|
||||
BtnLogin.OnAddClickListener += OnBtnLoginClick;
|
||||
BtnLogin.OnAddEnterListener += OnBtnLoginEnter;
|
||||
BtnLogin.OnAddExitListener += OnBtnLoginExit;
|
||||
}
|
||||
BtnClose = FindUICtrlByName<SFUI_Button>("BtnClose");
|
||||
BagListView = FindUICtrlByName<SFUI_ScrollRect>("BagListView");
|
||||
|
||||
// ✅ 按钮事件放在 OnRunAwake(先取消再注册防止重复)
|
||||
BtnClose.OnAddClickListener -= OnBtnClose;
|
||||
BtnClose.OnAddClickListener += OnBtnClose;
|
||||
|
||||
// ✅ 列表事件也放在 OnRunAwake
|
||||
BagListView.OnAddBeginDragListener -= OnBeginDrag;
|
||||
BagListView.OnAddBeginDragListener += OnBeginDrag;
|
||||
}
|
||||
|
||||
protected override void OnOpen(Action _onOpenComplete)
|
||||
{
|
||||
base.OnOpen(_onOpenComplete);
|
||||
// OnOpen: 注册CTC事件监听(每次打开调用)
|
||||
HFFunCatalogue.Event.CTCEvent.AddListener<HFEvent_CTC_LoginResult>(
|
||||
enHFCTCEvent.LoginResult, OnLoginResult);
|
||||
// ✅ 全局CTC事件放在 OnOpen
|
||||
HFFunCatalogue.Event.TCEvent.AddListener<HFEvent_BagItemUpdate>(
|
||||
enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
|
||||
}
|
||||
|
||||
protected override void OnClose(Action _onCloseComplete)
|
||||
{
|
||||
// OnClose: 移除事件监听(每次关闭调用)
|
||||
if (BtnLogin != null)
|
||||
{
|
||||
BtnLogin.OnAddClickListener -= OnBtnLoginClick;
|
||||
BtnLogin.OnAddEnterListener -= OnBtnLoginEnter;
|
||||
BtnLogin.OnAddExitListener -= OnBtnLoginExit;
|
||||
}
|
||||
|
||||
HFFunCatalogue.Event.CTCEvent.RemoveListener<HFEvent_CTC_LoginResult>(
|
||||
enHFCTCEvent.LoginResult, OnLoginResult);
|
||||
|
||||
// ✅ 全局CTC事件在 OnClose 取消
|
||||
HFFunCatalogue.Event.TCEvent.RemoveListener<HFEvent_BagItemUpdate>(
|
||||
enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
|
||||
base.OnClose(_onCloseComplete);
|
||||
}
|
||||
|
||||
void OnBtnLoginClick(GameObject go)
|
||||
{
|
||||
// 处理登录逻辑 - 使用框架标准调用方式
|
||||
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)
|
||||
{
|
||||
// 处理登录结果
|
||||
}
|
||||
private void OnBtnClose(GameObject go) { /* 按钮点击处理 */ }
|
||||
private void OnBeginDrag(GameObject go) { /* 拖拽处理 */ }
|
||||
private void OnBagItemUpdate(IHFEventArg<enHFCTCEvent> arg) { /* 数据更新处理 */ }
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 框架封装UI组件列表
|
||||
### 1.3 防重复注册原理
|
||||
|
||||
| 组件名 | 基类 | 说明 |
|
||||
|-------|------|------|
|
||||
| `SFUI_Button` | `AbsSFUI_Button : Button` | 按钮组件 |
|
||||
| `SFUI_Text` | `AbsSFUI_Text : Text` | 文本组件 |
|
||||
| `SFUI_Image` | `AbsSFUI_Image : Image` | 图片组件 |
|
||||
| `SFUI_Toggle` | `AbsSFUI_Toggle : Toggle` | 开关组件 |
|
||||
| `SFUI_ScrollRect` | `AbsSFUI_ScrollRect : ScrollRect` | 滚动区域 |
|
||||
| `SFUI_InputField` | `AbsSFUI_InputField : InputField` | 输入框 |
|
||||
```csharp
|
||||
// 先取消注册,再添加注册
|
||||
BtnLogin.OnAddClickListener -= OnBtnLoginClick; // 防止重复注册
|
||||
BtnLogin.OnAddClickListener += OnBtnLoginClick; // 安全注册
|
||||
```
|
||||
|
||||
### 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)` | 鼠标进入 |
|
||||
| `OnAddExitListener` | `Exit(GameObject go)` | 鼠标退出 |
|
||||
| `OnAddPointerUpListener` | `PointerUp(GameObject go)` | 指针抬起 |
|
||||
| `OnAddBeginDragListener` | `BeginDrag(GameObject go)` | 开始拖拽 |
|
||||
| `OnAddEndDragListener` | `EndDrag(GameObject go)` | 结束拖拽 |
|
||||
|
||||
---
|
||||
|
||||
## 二、事件系统分类
|
||||
|
||||
### 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
|
||||
**版本**: v1.1
|
||||
**适用范围**: GiftGameX项目业务开发人员
|
||||
@@ -5,52 +5,67 @@
|
||||
### 1.1 窗口创建流程
|
||||
|
||||
```csharp
|
||||
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/Login/LoginWindow.prefab")]
|
||||
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Dynamic, isIgnoreCloseByESC = false)]
|
||||
public class LoginWindow : AbsHFUIWindow
|
||||
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/Bag/BagWindow.prefab")]
|
||||
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Fixed, isIgnoreCloseByESC = false)]
|
||||
public class BagWindow : AbsHFUIWindow
|
||||
{
|
||||
// ========== UI组件 ==========
|
||||
private SFUI_Button BtnLogin;
|
||||
private SFUI_InputField InputName;
|
||||
private SFUI_InputField InputPassword;
|
||||
private SFUI_TextMeshProUGUI TxtTitle;
|
||||
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组件引用(变量名与组件名保持一致)
|
||||
BtnLogin = FindUICtrlByName<SFUI_Button>("BtnLogin");
|
||||
InputName = FindUICtrlByName<SFUI_InputField>("InputName");
|
||||
InputPassword = FindUICtrlByName<SFUI_InputField>("InputPassword");
|
||||
TxtTitle = FindUICtrlByName<SFUI_TextMeshProUGUI>("TxtTitle");
|
||||
// ✅ 初始化UI组件引用
|
||||
BtnClose = FindUICtrlByName<SFUI_Button>("BtnClose");
|
||||
BagListView = FindUICtrlByName<SFUI_ScrollRect>("BagListView");
|
||||
tips = BindUI<BagTips, SFUI_Image>("BagTips");
|
||||
|
||||
// 绑定按钮事件
|
||||
if (BtnLogin != null)
|
||||
{
|
||||
BtnLogin.OnAddClickListener += OnBtnLoginClick;
|
||||
}
|
||||
// ✅ 按钮事件绑定(带防重复注册保护)
|
||||
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)
|
||||
{
|
||||
// 取消事件监听
|
||||
if (BtnLogin != null)
|
||||
{
|
||||
BtnLogin.OnAddClickListener -= OnBtnLoginClick;
|
||||
}
|
||||
// ✅ 取消全局事件监听
|
||||
HFFunCatalogue.Event.TCEvent.RemoveListener<HFEvent_BagItemUpdate>(
|
||||
enHFCTCEvent.BagItemUpdate, OnBagItemUpdate);
|
||||
|
||||
// ✅ 清理资源
|
||||
tips.Clear();
|
||||
|
||||
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
|
||||
// 方式1:直接打开(无回调)
|
||||
HFFunCatalogue.UIManager.OpenWindow<LoginWindow>();
|
||||
HFFunCatalogue.UIManager.OpenWindow<BagWindow>();
|
||||
|
||||
// 方式2:打开并获取窗口实例(推荐)
|
||||
HFFunCatalogue.UIManager.OpenWindow<LoginWindow>((win, args) => {
|
||||
// win: 打开的窗口实例
|
||||
// args: 传入的额外参数
|
||||
HFFunCatalogue.UIManager.OpenWindow<BagWindow>((win, args) => {
|
||||
Debug.Log("窗口打开完成");
|
||||
});
|
||||
|
||||
// 方式3:带额外参数打开
|
||||
object[] extraArgs = new object[] { "param1", 123 };
|
||||
HFFunCatalogue.UIManager.OpenWindow<LoginWindow>((win, args) => {
|
||||
HFFunCatalogue.UIManager.OpenWindow<BagWindow>((win, args) => {
|
||||
// 使用窗口实例
|
||||
}, extraArgs);
|
||||
```
|
||||
@@ -80,12 +93,32 @@ HFFunCatalogue.UIManager.OpenWindow<LoginWindow>((win, args) => {
|
||||
|
||||
### 2.1 生命周期方法
|
||||
|
||||
| 方法 | 调用时机 | 说明 |
|
||||
|-----|---------|------|
|
||||
| `OnRunAwake` | 窗口创建时调用一次 | 初始化组件引用 |
|
||||
| `OnOpen` | 每次打开窗口时调用 | 注册事件、刷新数据 |
|
||||
| `OnClose` | 每次关闭窗口时调用 | 取消事件、清理资源 |
|
||||
| `OnDestroy` | 窗口销毁时调用 | 释放资源 |
|
||||
| 方法 | 调用时机 | 说明 | 推荐操作 |
|
||||
|-----|---------|------|---------|
|
||||
| `OnRunAwake` | 窗口创建时调用一次 | 初始化组件引用 | **绑定按钮事件、列表初始化** |
|
||||
| `OnOpen` | 每次打开窗口时调用 | 注册事件、刷新数据 | **注册全局TC事件、初始化数据** |
|
||||
| `OnClose` | 每次关闭窗口时调用 | 取消事件、清理资源 | **取消全局TC事件、清理UI状态** |
|
||||
| `OnDestroy` | 窗口销毁时调用 | 释放资源 | **释放非托管资源** |
|
||||
|
||||
### 2.2 生命周期流程图
|
||||
|
||||
```
|
||||
窗口创建
|
||||
↓
|
||||
OnRunAwake() ──→ 初始化组件、绑定按钮事件
|
||||
↓
|
||||
窗口打开(可多次)
|
||||
↓
|
||||
OnOpen() ──→ 注册TC事件、刷新数据
|
||||
↓
|
||||
窗口关闭(可多次)
|
||||
↓
|
||||
OnClose() ──→ 取消TC事件、清理资源
|
||||
↓
|
||||
窗口销毁
|
||||
↓
|
||||
OnDestroy() ──→ 释放资源
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -100,7 +133,96 @@ HFFunCatalogue.UIManager.OpenWindow<LoginWindow>((win, args) => {
|
||||
| `isNeedMask` | 是否需要遮罩 | true |
|
||||
| `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项目业务开发人员
|
||||
@@ -7,37 +7,31 @@
|
||||
```csharp
|
||||
SFUI_Button btn = GetComponent<SFUI_Button>();
|
||||
|
||||
// 添加点击事件
|
||||
// 添加点击事件(带防重复注册保护)
|
||||
btn.OnAddClickListener -= OnBtnClick;
|
||||
btn.OnAddClickListener += OnBtnClick;
|
||||
|
||||
// 添加鼠标进入/退出事件
|
||||
btn.OnAddEnterListener -= OnBtnEnter;
|
||||
btn.OnAddEnterListener += OnBtnEnter;
|
||||
|
||||
btn.OnAddExitListener -= OnBtnExit;
|
||||
btn.OnAddExitListener += OnBtnExit;
|
||||
|
||||
// 设置按钮状态
|
||||
btn.SetSelfGray(true); // 设置灰色不可用
|
||||
btn.interactable = false; // 设置不可交互
|
||||
btn.SetSelected(true); // 设置选中状态
|
||||
|
||||
void OnBtnClick(GameObject go)
|
||||
{
|
||||
// 处理点击
|
||||
}
|
||||
|
||||
void OnBtnEnter(GameObject go)
|
||||
{
|
||||
// 鼠标进入
|
||||
}
|
||||
|
||||
void OnBtnExit(GameObject go)
|
||||
{
|
||||
// 鼠标退出
|
||||
}
|
||||
void OnBtnClick(GameObject go) { /* 处理点击 */ }
|
||||
void OnBtnEnter(GameObject go) { /* 鼠标进入 */ }
|
||||
void OnBtnExit(GameObject go) { /* 鼠标退出 */ }
|
||||
```
|
||||
|
||||
### 1.2 SFUI_Text组件
|
||||
### 1.2 SFUI_TextMeshProUGUI组件
|
||||
|
||||
```csharp
|
||||
SFUI_Text txt = GetComponent<SFUI_Text>();
|
||||
SFUI_TextMeshProUGUI txt = GetComponent<SFUI_TextMeshProUGUI>();
|
||||
|
||||
// 设置文本
|
||||
txt.text = "Hello World";
|
||||
@@ -58,16 +52,20 @@ txt.outlineWidth = 2;
|
||||
```csharp
|
||||
SFUI_Image img = GetComponent<SFUI_Image>();
|
||||
|
||||
// 加载Sprite
|
||||
HFFunCatalogue.Sprite.LoadSprite("Icon_Player", sprite => {
|
||||
img.sprite = sprite;
|
||||
});
|
||||
// 加载Sprite(使用框架封装方法)
|
||||
img.HFSetItemIcon("Icon_Player");
|
||||
|
||||
// 加载远程图片
|
||||
img.HFSetUrlSprite("https://example.com/icon.png");
|
||||
|
||||
// 设置透明度
|
||||
img.SetAlpha(0.5f);
|
||||
|
||||
// 设置灰度
|
||||
img.SetSelfGray(true);
|
||||
|
||||
// 清空Sprite
|
||||
img.HFClearSprite();
|
||||
```
|
||||
|
||||
### 1.4 SFUI_Toggle组件
|
||||
@@ -76,6 +74,7 @@ img.SetSelfGray(true);
|
||||
SFUI_Toggle toggle = GetComponent<SFUI_Toggle>();
|
||||
|
||||
// 添加状态改变事件
|
||||
toggle.onValueChanged.RemoveListener(OnToggleValueChanged);
|
||||
toggle.onValueChanged.AddListener(OnToggleValueChanged);
|
||||
|
||||
void OnToggleValueChanged(bool isOn)
|
||||
@@ -84,21 +83,38 @@ void OnToggleValueChanged(bool isOn)
|
||||
}
|
||||
```
|
||||
|
||||
### 1.5 SFUI_ScrollRect组件
|
||||
### 1.5 SFUI_ScrollRect组件(列表绑定模式)
|
||||
|
||||
```csharp
|
||||
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; }, // 实例化模板
|
||||
OnUpdateItem, // 更新回调
|
||||
(item) => { // 组件获取
|
||||
return item.gameObject.HFGetOrAddSimulateBehaviour<BagItemSlot>();
|
||||
}
|
||||
);
|
||||
|
||||
// 添加滚动事件
|
||||
scroll.onValueChanged.AddListener(OnScrollValueChanged);
|
||||
// 刷新列表
|
||||
scroll.ShowView(); // 显示视图
|
||||
scroll.RefreshView(null); // 刷新当前视图
|
||||
scroll.ScrollToIndex(0); // 滚动到指定索引
|
||||
|
||||
void OnScrollValueChanged(Vector2 value)
|
||||
// 添加拖拽事件
|
||||
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_Text | TxtTitle |
|
||||
| SFUI_Image | ImgAvatar |
|
||||
| SFUI_Button | BtnLogin, BtnClose |
|
||||
| SFUI_TextMeshProUGUI | TxtTitle, TxtNum |
|
||||
| SFUI_Image | ImgIcon, ImgKuang |
|
||||
| SFUI_Toggle | ToggleSelect |
|
||||
| SFUI_ScrollRect | ScrollContent |
|
||||
| SFUI_InputField | InputName |
|
||||
| SFUI_ScrollRect | BagListView, ScrollContent |
|
||||
| SFUI_InputField | InputName, InputPassword |
|
||||
| SFUI_GridLayoutGroup | GridItemContainer |
|
||||
|
||||
**命名约定**:
|
||||
- 变量名 = 组件名(保持完全一致)
|
||||
- 首字母大写,采用 PascalCase 命名风格
|
||||
|
||||
**使用示例**:
|
||||
```csharp
|
||||
BtnLogin = FindUICtrlByName<SFUI_Button>("BtnLogin");
|
||||
TxtTitle = FindUICtrlByName<SFUI_Text>("TxtTitle");
|
||||
ImgAvatar = FindUICtrlByName<SFUI_Image>("ImgAvatar");
|
||||
```
|
||||
- 前缀说明:Btn(按钮)、Txt(文本)、Img(图片)、Toggle(开关)、Scroll(滚动)、Input(输入框)、Grid(网格)
|
||||
|
||||
### 2.2 层级结构
|
||||
|
||||
@@ -135,10 +146,10 @@ ImgAvatar = FindUICtrlByName<SFUI_Image>("ImgAvatar");
|
||||
WindowRoot/
|
||||
├── bg/ # 背景层
|
||||
├── content/ # 内容层
|
||||
│ ├── header/ # 头部
|
||||
│ ├── body/ # 主体
|
||||
│ └── footer/ # 底部
|
||||
└── top/ # 顶层(弹窗、提示等)
|
||||
│ ├── header/ # 头部(标签页、标题)
|
||||
│ ├── body/ # 主体(列表、内容区)
|
||||
│ └── footer/ # 底部(操作按钮)
|
||||
└── top/ # 顶层(弹窗、提示、遮罩)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -147,14 +158,16 @@ WindowRoot/
|
||||
|
||||
| 组件名 | 基类 | 扩展功能 |
|
||||
|-------|------|---------|
|
||||
| `SFUI_Button` | Button | 灰色状态、多事件委托 |
|
||||
| `SFUI_Button` | Button | 灰色状态、多事件委托、选中状态 |
|
||||
| `SFUI_Text` | Text | 描边、阴影扩展 |
|
||||
| `SFUI_Image` | Image | 灰度、透明度快捷设置 |
|
||||
| `SFUI_TextMeshProUGUI` | TextMeshProUGUI | 继承原生功能 |
|
||||
| `SFUI_Image` | Image | 灰度、透明度快捷设置、Sprite加载 |
|
||||
| `SFUI_Toggle` | Toggle | 状态改变事件 |
|
||||
| `SFUI_ScrollRect` | ScrollRect | 滚动优化 |
|
||||
| `SFUI_ScrollRect` | ScrollRect | **列表绑定模式、滚动优化** |
|
||||
| `SFUI_InputField` | InputField | 输入限制 |
|
||||
| `SFUI_Slider` | Slider | 数值范围限制 |
|
||||
| `SFUI_Dropdown` | Dropdown | 选项管理 |
|
||||
| `SFUI_GridLayoutGroup` | GridLayoutGroup | 网格布局 |
|
||||
|
||||
---
|
||||
|
||||
@@ -162,13 +175,82 @@ WindowRoot/
|
||||
|
||||
### 4.1 优化建议
|
||||
|
||||
- **对象池复用**:频繁创建的UI元素使用对象池
|
||||
- **图集打包**:将小图标打包到SpriteAtlas
|
||||
- **层级优化**:合理设置Canvas层级
|
||||
- **避免过度绘制**:减少重叠UI元素
|
||||
- **批量操作**:使用RectTransform批量修改
|
||||
| 优化项 | 说明 | 实现方式 |
|
||||
|-------|------|---------|
|
||||
| **对象池复用** | 频繁创建的UI元素使用对象池 | 使用 `HFClassEntityManager` |
|
||||
| **图集打包** | 将小图标打包到SpriteAtlas | 在Unity中配置SpriteAtlas |
|
||||
| **层级优化** | 合理设置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项目业务开发人员
|
||||
Reference in New Issue
Block a user