4.9 KiB
4.9 KiB
完成页「强力侧滑版」— 审查报告(禁止应用)
审查对象:粉紫勋章视觉 + RobustSwipeBackEnabler(didMove + viewDidAppear 双节点强制开启侧滑)
结论:仅审查,不修改仓库内任何文件。
一、问题与方案对应
| 问题 | 方案 | 审查结论 |
|---|---|---|
| 隐藏导航栏后侧滑返回失效 | 用 UIViewController 子类在 didMove(toParent:) 与 viewDidAppear 两处调用 enableGesture() |
✅ 思路正确,双节点可提高找回手势的概率 |
| 之前 SwipeBackEnabler 时机不对或被覆盖 | 使用自定义 SwipeBackController 继承 UIViewController,在生命周期中多次执行 |
✅ 比仅用 updateUIViewController 的 Representable 更稳 |
二、强力侧滑实现审查
2.1 RobustSwipeBackEnabler + SwipeBackController
- Representable:
makeUIViewController返回SwipeBackController(),updateUIViewController为空,符合「只挂一个控制器做生命周期」的用法。 - SwipeBackController:
didMove(toParent:):视图被加入/移出父控制器时调用,此时通常已进入导航栈,可拿到navigationController。viewDidAppear:每次该页显示时再执行一次,可应对 SwiftUI 更新或系统把手势关掉的情况。
- enableGesture():
nc.interactivePopGestureRecognizer?.delegate = nil+isEnabled = true是常见做法,用于在隐藏导航栏时恢复全屏侧滑。逻辑正确。
2.2 潜在注意点(非否决项)
- 视图层级:
.background(RobustSwipeBackEnabler())会把SwipeBackController的 view 作为 CompletionView 的底层。SwiftUI 的 NavigationStack 对应底层会有一个UINavigationController,self.navigationController应是该栈,因此一般能正确找到。若将来把 CompletionView 放在非 NavigationStack 的容器里,需再确认navigationController是否仍为预期栈。 - 多次执行:
didMove/viewDidAppear可能被多次调用(例如 SwiftUI 重绘、present 方式变化),重复执行enableGesture()无副作用,可接受。 - 真机验证:建议在真机上从「发现 / 技能 / 我的」三个 Tab 分别进入完成页,各做几次右滑返回,确认无偶发失效;若仍有失效,可再在
viewWillAppear或短延迟DispatchQueue.main.async中补一次enableGesture()。
三、视觉与交互审查
3.1 与需求对照
| 需求 | 实现 | 结论 |
|---|---|---|
| 粉紫勋章:点前灰色+「完成」,点后粉紫+「共完成 XX 节」 | 未激活:灰底 + 灰边 + 「完成」;激活:粉紫渐变圆 + 白字「共完成 / N 小节」+ 冲击波 | ✅ 一致 |
| 顶部无返回按钮,只有标题「已完成」 | ZStack 中仅 Text("已完成"),无 Button |
✅ 一致 |
| 底部淡蓝按钮、无箭头 | Text("回到我的内容"),.foregroundColor(.brandVital),Capsule().fill(Color.brandVital.opacity(0.08)),无 SF Symbol |
✅ 一致 |
| 右滑回最后一节 | 依赖 RobustSwipeBackEnabler | ✅ 见上 |
| 底部按钮回技能页根 | handleReturnToRoot() → navStore.switchToGrowthTab() |
✅ 一致 |
3.2 配色与 DesignSystem
- 方案中本地定义:
cyberPink = Color(red: 1.0, green: 0.25, blue: 0.50)→ 等价#FF4081cyberPurple = Color(red: 0.54, green: 0.31, blue: 1.0)→ 等价#8A4FFF
- DesignSystem 中已有:
Color.cyberNeon=#FF4081Color.cyberIris=#8A4FFF
- 建议(可选):将勋章渐变的
cyberPink/cyberPurple改为Color.cyberNeon/Color.cyberIris,避免重复定义并统一设计系统;若你希望完成页与 DesignSystem 解耦则可保留当前写法。
3.3 其他细节
- 冲击波:
rippleScale从 1.0 到 1.8、rippleOpacity从 1.0 到 0,时长 0.8s,视觉合理。 - 震动:
UIImpactFeedbackGenerator(style: .heavy),与「点亮」动作匹配。 - 底部按钮常驻显示(不依赖
isActive),与「回到我的内容」随时可点一致。
四、接口与调用方
- CompletionView 仍为三参:
courseId,courseTitle,completedLessonCount,依赖@EnvironmentObject navStore。 - GrowthView / ProfileView / DiscoveryView 无需改构造或传参。
五、审查结论汇总
| 项 | 结论 |
|---|---|
| 强力侧滑方案 | 双生命周期节点(didMove + viewDidAppear)合理,实现正确;建议真机多入口验证,必要时可再加 viewWillAppear 或短延迟兜底。 |
| 粉紫勋章视觉 | 与描述一致;可选改用 DesignSystem 的 cyberNeon/cyberIris 统一色值。 |
| 顶部 / 底部 / 交互 | 符合「无返回、仅标题、淡蓝按钮无箭头、底部回技能页根」的要求。 |
| 全量替换范围 | 仅替换 CompletionView.swift 即可;VerticalScreenPlayerView 等不动。 |
未对仓库内任何文件进行修改。