1.为什么领取奖励逻辑在 SubView,而充值任务逻辑在 MainView?
FirstCharge_SubView 是整个首充功能的外层容器,负责管理所有首充二级页签、当前选中状态、子页面创建和红点,因此它监听 GET_TASK_REWARD 并处理的并不是“如何领取奖励”,而是奖励领取成功后的全局刷新:保留当前页签,重新读取首充任务和配置数据,重建页签状态及当前内容页,并更新相关红点;真正的充值和领奖业务则放在 FirstCharge_MainView 及奖励 Cell 中,因为它们持有当前页签的任务数组和具体 UI 控件,负责判断充值任务是否完成、切换“充值/奖励已解锁”状态、响应充值按钮、展示每条任务对应的奖励以及发起领奖请求。简单来说,MainView 负责当前页签内部“如何充值、如何展示和领取奖励”,SubView 负责领奖成功后“如何让整个首充模块的页签、页面和红点保持同步”
FirstCharge_SubView
├─ 构建左侧页签
├─ 选择当前页签
└─ 创建当前内容页
├─ FirstCharge_MainView
└─ FirstChagre_SixCharge_SubVIew

FirstCharge_SubView:

#一、整体职责
这份代码主要完成5件事:
请求首充任务数据;
读取首充配置 Map 和任务 Map;
根据配置生成左侧二级页签;
决定默认选中哪个页签;
根据当前页签动态创建对应的内容子页面。

1
2
3
4
5
6
FirstCharge_SubView
├─ 左侧页签:w_list_GiftTag
└─ 内容插槽:w_nameSlot_SubView
├─ 普通首充页面
└─ SixCharge师徒页面

我按照四个部分的调用链进行拆解
第一个部分页面被打开的初始化OnOpen()
第二个部分用户切换页签触发的事件OnSecondTabChanged
第三个部分用户领取完奖励触发的事件OnReqNewData
第四个部分首充奖励返回OnFirstChargeInfoReady
四条调用链对比

调用链 触发来源 重新读取Model 重建页签 重建内容页 保留当前页签
OnOpen 页面打开 是 是 是 首次通常没有
OnSecondTabChanged 用户点击页签 否 否,只更新选中 是 切到指定页签
OnReqNewData 领取任务奖励 是 是 是 是
OnFirstChargeInfoReady 首充数据返回 是 是 是 有则保留

OnOpen调用链:界面打开开始按顺序执行,创建页面(默认的界面)并且读取配置数据同时初始化ItemTab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
OnOpen(Data)
├─ 保存外部参数
├─ OnInitializedEvent()
├─ InitData()
├─ InitEvent()
└─ InitUI()
├─ ReqFirstChargeTaskInfo()
└─ RefreshFirstChargeUI()
├─ InitTaskData()
├─ 校验任务Map
├─ 校验配置Map
├─ InitSecondTabUI()
│ ├─ 清空旧状态
│ ├─ BuildSecondTabListData() --将获取的数据读取到并且存入到本地表中,方便使用
│ ├─ SetSelectedSecondId() --选择默认页签,默认是第一个
│ ├─ 更新页签选中状态
│ └─ 刷新左侧页签ListView
├─ SwitchSubView()
│ ├─ 删除旧子页面,传入角色预览等
│ ├─ 查找蓝图/Lua路径
│ └─ 创建当前内容子页面
└─ 更新首充红点

OnSecondTabChanged调用链:点击切换Item,清楚就Widget,切换新界面,并且执行新界面的OnOpen调用链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
用户点击左侧页签
→ 派发SecondTabChanged(secondTagId)
→ OnSecondTabChanged(secondTagId)
├─ 检查ID
├─ 从TagInfoMap查找页签
├─ 判断是否重复点击
├─ 更新SelectedSecondId
├─ 更新CurTabInfo
├─ 更新所有页签isSelected
├─ 刷新左侧页签ListView
└─ SwitchSubView()
├─ 删除旧内容页
└─ 创建新内容页

OnReqNewData调用链:任务奖励领取成功后调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
用户领取首充奖励
→ 服务端返回任务奖励结果
→ 派发GET_TASK_REWARD
→ OnReqNewData()
├─ 记录当前页签ID
└─ RefreshFirstChargeUI(selectedId)
├─ InitTaskData()重新读取任务Map和配置Map
├─ 校验任务Map
├─ 校验配置Map
├─ InitSecondTabUI()重建左侧页签数据
│ ├─ 清空旧状态
│ ├─ BuildSecondTabListData() --将获取的数据读取到并且存入到本地表中,方便使用
│ ├─ SetSelectedSecondId() --走preferredSecondId判断,将preferredSecondId赋值当前选择的页签id,防止跳转
│ ├─ 更新页签选中状态
│ └─ 刷新左侧页签ListView
├─ SwitchSubView()
│ ├─ 删除旧子页面,传入角色预览等
│ ├─ 查找蓝图/Lua路径
│ └─ 创建当前内容子页面
└─ 更新首充红点


OnFirstChargeInfoReady调用链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
OnOpen
→ ReqFirstChargeTaskInfo()
→ 服务端返回首充数据
→ FirstChargeModel整理配置和任务Map
→ 派发GET_FIRST_CHARGE_INFO
→ OnFirstChargeInfoReady()
└─ RefreshFirstChargeUI(SelectedSecondId) --存在2种情况首次打开和页面已经有缓存并选中了页签,此时仍然保留此时的页签,不进行跳转。后续过程跟OnReqNewData调用链一样
├─ 重新读取任务Map
├─ 重新读取配置Map
├─ 校验数据
├─ InitSecondTabUI()重建左侧页签数据
│ ├─ 清空旧状态
│ ├─ BuildSecondTabListData() --将获取的数据读取到并且存入到本地表中,方便使用
│ ├─ SetSelectedSecondId() --走preferredSecondId判断,将preferredSecondId赋值当前选择的页签id,防止跳转
│ ├─ 更新页签选中状态
│ └─ 刷新左侧页签ListView
├─ SwitchSubView()
│ ├─ 删除旧子页面,传入角色预览等
│ ├─ 查找蓝图/Lua路径
│ └─ 创建当前内容子页面
└─ 更新首充红点

FirstCharge_TabItem

FirstCharge_TabItem.lua 是 FirstCharge_SubView 左侧二级页签 ListView 中的单个页签 Cell,负责接收一个 tagInfo、显示页签图标/名称/红点/选中效果,并在用户点击时把当前页签 ID 通过事件传回外层 FirstCharge_SubView。它不负责创建内容页面,也不负责处理首充任务或奖励。ListView Cell:只负责单条页签数据的显示和点击事件,不管理整个页签列表。

OnOpen调用链:这是每个页签 Cell 被 ListView 创建时执行的初始化入口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FirstCharge_SubView构造页签数据
→ ListSetDatas(w_list_GiftTag, SubTabDataList)
→ ListView创建FirstCharge_TabItem
→ FirstCharge_TabItem:OnOpen(tagInfo)
├─ 保存tagInfo
├─ OnInitializedEvent()
│ └─ 绑定页签按钮
├─ InitData()
│ ├─ 取得页签ID
│ ├─ 取得页签名称
│ └─ 取得选中状态
├─ InitEvent()
└─ InitUI()
└─ RefreshUI()
├─ 设置页签图标
├─ 设置图标显隐
├─ 设置页签名称
├─ 设置选中效果
└─ 初始化红点

FirstCharge_SixCharge_SubView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1.FirstCharge_SubView:SwitchSubView(): --创建SixCharge子页面
self.CurSubView = self:AddWidgetAndLua(assetPath,luaPath,self.bp.w_nameSlot_SubView,self.CurTabInfo)
--CurTabInfo包含firstChargeData = 某个首充配置对应的任务数组, firstChargeConfigData = 当前首充配置,previewActor = 预览角色,
2.调用继承的父类的Open,其中SixCharge 重写了OnInitializedEvent(),实际是自己的按钮绑定
3.执行父类InitUI,包含InitTaskData,InitItemUI,InitListUI,SetRechargeBtnVisibility,InitModelUI
4.提取当前的页签数据InitTaskData
self.FirstChargeDataMap = self.Data.firstChargeData
self.FirstChargeConfigData = self.Data.firstChargeConfigData
5.动态调用SixCharge的InitListUI,重写了父类的逻辑,所以走自己的逻辑
6.构造UI数据并判断首充状态
遍历任务数组for i = 1, count do local taskData = self.FirstChargeDataMap[i]
判断任务是否完成
7.填充列表


完整流程:
打开 SixCharge 页面后,执行继承自 FirstCharge_MainView 的 OnOpen 和初始化流程。
父类 InitUI 从页签参数中取得当前首充配置对应的任务数组,然后动态调用 SixCharge 重写的 InitListUI。
SixCharge 根据任务数量选择三日分组布局或普通列表布局,遍历任务数组构造 ListView UI 数据,同时根据任务状态判断是否显示充值按钮。
三日布局再按照 2/4/2 拆分 UI 数据,并分别填充三个 ListView。
每个奖励 Cell 最后从对应任务对象的 GetTaskRewards() 中取得奖励内容并展示。

FirstChagre_MainView

FirstCharge_MainView 接收到的是当前页签的 CurTabInfo,包含id = 当前首充配置ID,firstChargeData = 当前配置对应的任务数组,firstChargeConfigData = 当前首充配置,previewActor = 3D预览角色。

OnOpen调用链:首充包含2个界面,默认是这个界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FirstCharge_MainView:OnOpen(Data)
├─ 保存外层传入的当前页签数据
├─ OnInitializedEvent() --绑定充值按钮
├─ InitData() --初始化充值按钮状态
├─ InitEvent() --监听任务、领奖和弹窗事件
└─ InitUI()
├─ InitTaskData() --提取任务数组、首充配置和预览角色
├─ InitItemUI() --设置价格和货币图标
├─ InitListUI()
│ ├─ InitListData() --根据任务数量选择奖励列表
│ ├─ 判断是否已完成充值任务
│ └─ 填充奖励ListView
├─ SetRechargeBtnVisibility() --切换充值/奖励已解锁状态(控件切换器)
└─ InitModelUI()
└─ SetModelAnim() --设置角色套装、相机和动画

OnReceiveSameValueRewards调用链:在用户点击领取奖励时调用(说明首充的充值任务已经完成),用户点击奖励,传入taskValue代表奖励挡位,同时遍历任务列表3重条件进行检查是否完成,然后执行领取。点击一个奖励,批量全部领取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
奖励Item:OnClickedBtnGetReward()
├─ 获取任务条件目标值TaskValue
└─ 派发FirstChargeModel_ReceiveSameValueRewards
↓
FirstCharge_MainView:OnReceiveSameValueRewards(TaskValue)
├─ 遍历当前页签任务数组
├─ 查找相同TaskValue的任务
├─ 筛选已经完成、可以领取的任务
└─ TaskSystemModel:ReqGetTaskRewards(TaskIdList)
↓
服务端返回领取结果
└─ FirstCharge_SubView:OnReqNewData()
--重建页签和当前内容页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TaskSystem派发TASK_INFO_MAP_UPDATE_NOTICE
├─ FirstCharge_MainView:OnUpdateTaskInfo()
│ ├─ 检查当前页签是否有任务变化
│ └─ 更新首充页签和充值入口红点
│
└─ 奖励Item:RefreshRewardItem()
├─ 刷新奖励领取状态
└─ 派发FirstChargeModel_RefreshReward
↓
FirstCharge_MainView:RefreshRechargeBtnVisibility()
├─ IsShowRechargeBtn = false
└─ SetRechargeBtnVisibility()
--将充值区域切换为“奖励已解锁”


1
2
3
4
5
6
7
8
9
10
11
12
头像弹窗关闭
└─ 派发ON_CLOSE_WINDOW_IMMEDIATELY(WndName)
↓
FirstCharge_MainView:OnCloseWindowImmediately(WndName)
├─ 判断是否为头像相关弹窗
└─ SetModelAnim()
├─ RefreshPreviewUI()
│ ├─ 恢复首充套装
│ └─ 恢复Camera_Recharge相机
├─ ClearAnimTimer() --清除旧动画定时器
└─ 根据配置恢复角色动画


本文从 LearnByCompany 原始文档 自动同步。