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

6.4 KiB
Raw Blame History

StrayFog 框架 UI窗口开发指南

一、UI窗口基础

1.1 窗口创建流程

[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 窗口打开方式

// 方式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 层叠配置

[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Fixed, isIgnoreCloseByESC = false)]
//                ↑ Canvas层级                    ↑ 窗口层级

四、子组件开发

4.1 物品槽组件示例

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 提示框组件示例

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项目业务开发人员