8.5 KiB
8.5 KiB
完成页导航方案 — 实现后行为与影响说明
说明:实现方案后会变成什么样、会不会影响原有逻辑和展示、会不会导致其他地方出问题。不修改代码,仅作说明。
一、实现后会变成什么样
1. 进入完成页(两种方式,二选一或并存)
| 方式 | 当前 | 实现后(若保留占位页 + 加手势) |
|---|---|---|
| 左滑到「下一页」 | 最后一节再左滑 → 进入占位页(空白)→ 0.1s 后 push 完成页 | 不变:仍可滑到占位页,再由 onChange push |
| 在最后一节左滑 | 无 | 新增:在最后一节直接左滑(手势识别)→ 可设为「切到占位页再 push」或「直接 push 完成页」 |
若方案采用「删除占位页、仅手势」:
- 最后一节左滑 → 直接 push 完成页,不再出现空白占位页那一屏。
- TabView 只有真实课程页,不再有「多一页」的占位。
展示上:完成页本身 UI 不变(仍是当前 CompletionView 的 3D 卡片、打字机等);变的只是「怎么进」和「怎么回」。
2. 从完成页返回(核心变化)
| 操作 | 当前 | 实现后 |
|---|---|---|
| 顶部返回 (chevron) | dismiss() → 回到播放器(最后一节或占位页) |
可保持不变:仍 dismiss(),回到播放器 |
| 底部「继续学习」 | navStore.switchToGrowthTab() + dismiss() |
handleReturnToMap():navigationPath.removeLast(2) |
「继续学习」行为对比:
-
当前:
dismiss()→ 栈 pop 一层,回到 VerticalScreenPlayerView(当前 Tab 可能是占位页,onAppear里会切回最后一节)。switchToGrowthTab()→ 切到「技能」Tab,且 清空growthPath(growthPath = NavigationPath())。- 用户最终看到的是 技能 Tab 的根界面(课程列表),不是地图。
-
实现后:
removeLast(2)→ 一次 pop 掉「完成页」和「播放器」。- 栈变成:[MapView](或更短,视当前 path 而定)。
- 不调用
switchToGrowthTab(),所以不会清空 path,也不一定会切 Tab。 - 用户最终看到的是 当前 Tab 下的地图页(从哪个 Tab 进的,就还在哪个 Tab)。
总结:
- 实现后,点「继续学习」会直接回到地图,且保留在当前 Tab(发现 / 技能 / 我的)。
- 当前是回到课程列表(且强制在技能 Tab)。这是产品行为上的明确变化。
3. 三条入口分别会怎样
| 入口 | 当前栈(到完成页时) | 当前「继续学习」后 | 实现后「继续学习」后 |
|---|---|---|---|
| 技能 Tab | growthPath: [Map, Player, Completion] | 切到技能 Tab + 清空栈 → 课程列表 | 仍技能 Tab,栈 [Map] → 地图 |
| 发现 Tab | homePath: [Map, Player, Completion] | dismiss 回播放器;switchToGrowthTab 切到技能并清空 → 课程列表 | 仍发现 Tab,栈 [Map] → 地图 |
| 我的 Tab | profilePath: [Map, Player, Completion] | 同上 → 课程列表 | 仍我的 Tab,栈 [Map] → 地图 |
二、会不会影响原有逻辑和展示
1. 会改变的部分(有意为之)
- 底部按钮语义:「继续学习」从「回课程列表(并切到技能)」变为「回地图(且留在当前 Tab)」。
- 是否清空栈:不再在完成页里清空
growthPath,所以不会出现「从完成页一点就回到空白课程列表」。 - 是否切 Tab:不再强制切到技能 Tab;用户会留在发现 / 技能 / 我的中的当前 Tab。
若产品期望就是「完成课后回到地图、留在当前 Tab」,则与方案一致;若期望是「回到课程列表、且一定在技能 Tab」,则与当前一致,与实现后不一致,需要产品确认。
2. 可保持不变的部分
- 完成页 UI:3D 翻转卡片、打字机、顶部返回、按钮样式等都可以不改。
- 顶部返回:继续用
dismiss(),仍回到播放器,逻辑和展示都不变。 - 进入完成页的方式:若保留占位页,现有「滑到占位页再 push」仍可用;只是多了一种「最后一节左滑」的触发方式(若加手势)。
3. 依赖「当前行为」的地方
- NavigationStore.switchToGrowthTab():当前只在 CompletionView 的「继续学习」里被调用。实现后 CompletionView 不再调用它,不会影响其他使用处(因为别处没有用这个方法)。
- growthPath 被清空:当前只有「完成页点继续学习」会清空 growthPath。若没有「从完成页返回后依赖 growthPath 为空」的逻辑,则实现后不会破坏其它功能。
三、会不会导致其他地方出问题
1. 三个 Tab 的 navigationDestination(必须改)
- GrowthView / ProfileView / DiscoveryView 里
.completion分支都要给 CompletionView 传 Binding:
navigationPath: $navStore.growthPath/$navStore.profilePath/$navStore.homePath。 - 漏传或错传:
- 漏传 → 编译不通过(CompletionView 多了必选参数)。
- 错传(例如发现进的完成页却传了
growthPath)→ 点「继续学习」会 pop 错栈,可能白屏或回到错误 Tab。
- 结论:三处都必须改,且必须传当前栈对应的 path,否则会出问题。
2. 笔记流(NoteTreeView / NoteListView)— 不受影响
- 笔记流用的是 NoteNavigationDestination.player,打开的是 VerticalScreenPlayerView,且没有传 navigationPath(或传的是笔记自己的 path)。
- 在这些地方打开的播放器里,
navigationPath为 nil,现有逻辑里onChange里会guard let path = navigationPath else { return },不会 push CourseNavigation.completion。 - 因此:从笔记进的播放器,不会出现「滑到完成页」的 push(除非你后续在笔记流里也接 Course 的 completion)。
- 结论:实现完成页方案不会影响笔记流,也不会从笔记流误进完成页。
3. 从完成页返回时栈深度不足
- 正常流程栈至少为 [Map, Player, Completion],
removeLast(2)安全。 - 若将来有「深链、通知、分享」等直接打开 CompletionView,栈可能只有 [Completion],此时
path.count >= 2为假,应走兜底dismiss()。 - 方案里已建议保留
if navigationPath.count >= 2 { removeLast(2) } else { dismiss() },不会因为栈浅而崩溃,最多退回单层 pop。
4. 手势与 TabView 滑动
- 在最后一节加「左滑进完成页」时,与 TabView 自带的左滑翻页共用同一方向,可能冲突(例如:想翻页却触发了完成页,或想进完成页却只翻到占位页)。
- 若用「边缘左滑」或阈值(如 -60pt)、防抖,可减轻误触;需在真机多测。
- 结论:可能带来体验上的小问题(误触/难触),不是逻辑错误,可通过手势参数和测试收敛。
5. 其他使用 VerticalScreenPlayerView / CompletionView 的地方
- VerticalScreenPlayerView:除 GrowthView / ProfileView / DiscoveryView 外,仅在 NoteTreeView / NoteListView 出现,且走的是 NoteNavigationDestination,不涉及 CourseNavigation.completion,不受影响。
- CompletionView:只在这三个 Tab 的
navigationDestination(for: CourseNavigation.self)的.completion分支出现,没有其它调用点。 - 结论:只要三处传参正确,不会导致其它页面逻辑错误。
四、简要结论表
| 问题 | 结论 |
|---|---|
| 实现后会变成什么样? | 进入完成页可增加「最后一节左滑」触发;「继续学习」从「回课程列表 + 切技能 Tab」变为「直接回地图 + 保留当前 Tab」;可选去掉占位页。 |
| 会不会影响原有逻辑和展示? | 会:底部按钮语义和最终停留页(地图 vs 课程列表)、是否清栈/切 Tab 会变;顶部返回和完成页 UI 可保持不变。 |
| 会不会导致其他地方出问题? | 三处传 Binding 必须正确,否则会 pop 错栈;笔记流、其它使用点不受影响;栈浅时用 dismiss 兜底;手势可能与 TabView 滑动冲突,需真机调参。 |
建议:实现前与产品确认「继续学习」的预期是「回地图」还是「回课程列表」;若确认为回地图且保留当前 Tab,再按方案改并保证三处 path 传参一致。