Hero 开源库 CHANGELOG 深度解读:从 1.3.0 到 1.6.3 的版本演进与核心源码实现
【免费下载链接】HeroElegant transition library for iOS & tvOS项目地址: https://gitcode.com/gh_mirrors/he/Hero
Hero 是面向 iOS 与 tvOS 的优雅转场动画库,提供在 UIKit 复杂转场 API 之上的声明式封装(Hero.podspec)。本文以仓库根目录 CHANGELOG.md 为脉络,逐版本梳理 Hero 从 1.3.0 到 1.6.3 的关键变更,并结合 Sources 目录下的真实实现,解释每个里程碑背后的设计动机与工作原理。读完本文,你将理解 Hero 的快照(snapshot)机制、自定义转场 API 的演进、Swift 生态适配路径,以及如何在升级版本时评估对自身项目的影响。
版本演进总览:Hero 的四个关键阶段
从 CHANGELOG 可以清晰看出 Hero 的能力迭代分为四个阶段:
| 版本区间 | 阶段主题 | 代表性能力 |
|---|---|---|
| 1.3.0 – 1.3.1 | 转场 API 完善期 | completion 回调、delegate 链式转发、阴影与闪烁修复 |
| 1.4.0 – 1.5.0 | 语言与快照优化期 | Swift 4.2、自定义快照协议、RTL 语言支持 |
| 1.6.0 | 生态现代化里程碑 | Swift 5、Swift Package Manager、SwiftUI 支持 |
| 1.6.1 – 1.6.3 | 稳定性与平台扩展期 | Xcode 14 警告修复、anchorPoint 支持、visionOS 适配 |
下面按版本号逐一深入。
1.6.3:visionOS 适配与 CI/CD 修复
1.6.3 的核心提交是 "Adaption for visionOS",使 Hero 可以在 visionOS 平台构建。对应源码中可见的平台条件编译:例如 HeroTransition+UITabBarControllerDelegate.swift 中使用#if !os(visionOS)包裹相关逻辑,说明 Tab Bar 相关的 UIKit 转场协议在 visionOS 上不可用,需要条件编译隔离。同时该版本修复了 CI 构建矩阵(build.yml、test.yml更新 GitHub runner 环境)、处理 Xcode 14.0 引入的编译警告(Fix build warnings with Xcode 14.0、Fix lint warnings),并在 README 中补充了 API 文档链接与平台徽章。
对于使用 Swift Package Manager 集成的用户,该版本与 Package.swift 声明的平台要求一致——iOS 10.0+ 与 tvOS 10.0+。
1.6.2:anchorPoint 支持与构建警告清理
1.6.2 修复了 #717、#734、#735、#736、#739、#740 等多期 issue,并解决 Xcode 13.4.1 构建警告问题。其中最重要的功能变更是#742:为转场添加anchorPoint支持。
anchorPoint 在源码中的落地
anchorPoint已正式成为 Hero 目标状态(target state)的可配置属性。在 HeroTargetState.swift 中:
public var anchorPoint: CGPoint?该属性在转场匹配预处理阶段被自动设置。SourcePreprocessor.swift 中有如下逻辑:
if view.layer.anchorPoint != targetView.layer.anchorPoint { state.anchorPoint = targetView.layer.anchorPoint }即在两个视图通过 heroID 配对时,如果源视图与目标视图的layer.anchorPoint不一致,Hero 会把目标视图的 anchorPoint 写入目标状态,从而保证旋转、缩放等基于锚点的变换在转场中表现正确。同时,HeroContext.swift 在生成快照时也会显式同步锚点:
snapshot.layer.anchorPoint = view.layer.anchorPoint snapshot.layer.position = containerView.convert(view.layer.position, from: superview)快照系统与 anchorPoint 的配合
这段代码所在的snapshotView(for:)是 Hero 转场的核心:它先把源视图的圆角、透明度、阴影临时归零,按 HeroSnapshotType 生成快照,再把圆角、阴影、边框、zPosition、锚点等图层属性原样拷贝到快照层上,最后隐藏原视图并让快照参与动画。这也解释了为什么自定义anchorPoint的视图(如做旋转动画的卡片)在旧版本中会出现转场错位——快照层没有继承锚点,1.6.2 正是补齐了这一环。
1.6.1:依赖与文档维护
1.6.1 是维护型版本:将 CI 依赖迁移到 Mint(closes #703 Move CI depends to Mint,对应仓库根目录的 Mintfile 与 Makefile),修复 SPM 缺失导入问题(#704)、清理 README 死链(#708),并将文档中 Material Design 的动效时长与缓动链接更新为最新地址。
1.6.0:Swift 5、SPM、SwiftUI 与扩展目标支持
1.6.0 是 Hero 生态现代化的分水岭,四项重要能力在同版本落地:
- Swift 5 支持(#695):Hero.podspec 中
s.swift_version = '5.0',Package.swift 声明swiftLanguageVersions: [.v5],源码全面切换到 Swift 5 语法; - Swift Package Manager 支持(#628):仓库新增 Package.swift,定义
Hero库 target(path 指向Sources)与HeroTests测试 target(path 指向Tests),平台限定.tvOS(.v10)与.iOS(.v10); - SwiftUI 支持(#623):新增 SwiftUIMatchExample.swift 示例,通过
UIHostingController把 SwiftUI 视图嵌入 Hero 转场体系,演示了列表到详情页的 hero 匹配动画; - App Extension 目标支持(#681):使 Hero 可用于 Today Widget 等 extension 场景。
交互控制 API 的演进
1.6.0 还修复了三个行为问题,从中可以看到 Hero 交互模型的细节:
- #585:
replaceViewControllers现在会调用 completion——转场结束时 completion 一定会被触发; - #559:从当前进度恢复 property animator——交互转场中途释放手指后,动画从当前 fraction 继续而非从头开始;
- #465:键盘转场修复——输入框切换场景下的布局跳动问题。
1.5.0:自定义快照协议与 RTL 支持
1.5.0 引入了两个值得深入理解的能力(均由 @ManueGE 贡献)。
HeroCustomSnapshotView:让视图自定义自己的快照
新增协议HeroCustomSnapshotView,在 HeroContext.swift 中定义:
/// Allows a view to create their own custom snapshot when using **Optimized** snapshot public protocol HeroCustomSnapshotView { var heroSnapshot: UIView? { get } }快照生成时,只要视图采用.optimized(默认)快照类型,Hero 就会优先询问视图自身的快照:HeroContext.swift
if let customSnapshotView = view as? HeroCustomSnapshotView, let snapshotView = customSnapshotView.heroSnapshot { snapshot = snapshotView }这解决了一个真实痛点:.optimized快照为不同类型视图做了差异化优化(如无子视图的UIImageView直接克隆 image、半透明UINavigationBar剥离背景再快照、UIStackView走慢速渲染),但对带有 mask 或复杂自绘内容的视图,优化快照可能与真实外观不一致。此时让视图通过该协议提供自定义快照,能保证转场视觉完全正确。
RTL 语言支持(#520)
为从右向左书写的语言(如阿拉伯语、希伯来语)添加支持,转场方向逻辑不再硬编码为从左到右。这与 HeroTransition.swift 中defaultAnimationDirectionStrategy: HeroDefaultAnimationType.Strategy = .forceLeftToRight的默认策略互为补充——默认强制 LTR,但 RTL 环境下可配置适配。
另外 #521 让UIImageView的优化快照开始考虑子视图的隐藏状态:仅当view.subviews.filter({!$0.isHidden}).isEmpty时才走"克隆 image"的快速路径(HeroContext.swift),避免遗漏隐藏子视图导致快照与真实视图不一致。
1.4.0:Swift 4.2 支持
1.4.0 由 @rennarda 的 PR #534 引入 Swift 4.2 支持。这是 Swift 语言演进与 iOS 生态兼容性同步的常规步骤,为后续 1.6.0 的 Swift 5 迁移铺平道路。Swift 4.2 时代的 API 命名习惯(如hero.dismissViewController()、hero.replaceViewController(with:))至今仍保留在 UIViewController+Hero.swift 中,只是通过@available(*, renamed:)与@available(*, deprecated, renamed:)做了版本兼容标注。
1.3.1 与 1.3.0:completion 回调与内存管理修复
1.3.1:修复 retain cycle
#516 修复了因强引用previousNavigationDelegate与previousTabBarDelegate导致的内存泄漏。对应实现中,这两个 delegate 被声明为weak:UIViewController+Hero.swift
weak var previousNavigationDelegate: UINavigationControllerDelegate? weak var previousTabBarDelegate: UITabBarControllerDelegate?Hero 接管导航/标签转场时会把原来的 delegate 暂存,转场结束或hero.isEnabled = false时还原(同一文件 L76-L96)。如果这里用强引用,代理链就可能形成循环引用导致 VC 无法释放。
1.3.0:completion 参数与 delegate 转发
- #456:
dismissViewController与replaceViewController增加可选 completion 参数。在 UIViewController+Hero.swift 中,dismissViewController(completion:)会智能判断:如果当前 VC 在 Navigation Controller 栈中则执行popViewController(animated:),否则执行dismiss(animated:completion:);replaceViewController(with:completion:)则分三种场景替换——Navigation 栈顶、present 层级、UIWindow 根控制器; - #430:允许前一个
UINavigationControllerdelegate 继续处理 delegate 事件。见 HeroTransition+UINavigationControllerDelegate.swift,Hero 转发willShow/didShow给原始 delegate,避免接管后原有业务逻辑失效; - #440:修复快照裁切阴影。快照生成时阴影属性会被临时清零再恢复(HeroContext.swift),1.3.0 完善了恢复逻辑,保证带阴影的视图快照不会把阴影裁掉;
- f4dab9:修复 CALayer 动画闪烁,解决
CALayer动画在转场首帧的闪烁问题。
升级视角:completion 在源码中的完整生命周期
1.3.0 引入、1.6.0 修复的 completion 机制,是理解 Hero 转场收敛逻辑的钥匙。completion 由HeroTransition持有并统一回调:
- 转场启动时,HeroTransition+CustomTransition.swift 把用户 completion 包装进
completionCallback; - 转场结束时,HeroTransition+Complete.swift 的
complete(finished:)在清理所有临时状态(快照、动画器、progress 观察者)之后调用completionCallback?(finished)(L128); - 状态机在
complete末尾复位到.possible(state = .possible),isTransitioning重新变为false。
因此replaceViewController中会先检查hero.isTransitioning,若转场进行中则拒绝执行并提示先用Hero.shared.cancel(animated:false)或Hero.shared.end(animated:false)结束当前转场(UIViewController+Hero.swift)。这也是 1.6.0 #585 修复的意义:以往 completion 在某些替换场景不会触发,升级后可以在 completion 里可靠地执行后续业务逻辑。
配套示例与验证资源
如需在实践中观察这些能力,仓库提供了两代示例工程:
- Examples(Swift 5 时代):SwiftUIMatchExample.swift 演示 SwiftUI 转场,MatchExample.swift、MatchInCollectionExample.swift 演示 hero 匹配动画,AppStoreCardExample.swift 演示卡片式转场,BuiltInTransitionExample.swift 演示内置转场类型;
- LegacyExamples:Storyboard 驱动的历史示例(AppleHomePage、CityGuide、ImageGallery、ListToGrid、VideoPlayer 等),适合对照 1.6.0 之前的 API 形态;
- Tests/HeroTests.swift:覆盖字符串式 modifier 的解析器(Lexer + Parser),可验证
fade()、scale(0.5) translate(200, 0)这类声明式转场语法。
版本验证上,Hero.podspec 的s.version = '1.6.3'与 CHANGELOG 最新版本一致,可直接作为集成校验点:CocoaPods 用户应看到 1.6.3,SPM 用户则以 Package.swift 与 git tag 为准。
结语:CHANGELOG 折射出的工程演进逻辑
回看这份 CHANGELOG,Hero 的演进路径清晰可循:先用 completion 与 delegate 转发完善 API 的"可编程性"(1.3.x),再通过自定义快照协议解决真实视图的渲染保真问题(1.5.0),随后借助 Swift 5、SPM、SwiftUI 融入现代 Swift 生态(1.6.0),最后以 anchorPoint 支持、Xcode 新版本适配与 visionOS 适配完成跨平台与稳定性收尾(1.6.2 – 1.6.3)。对于仍在评估或正在升级 Hero 的开发者,这份 CHANGELOG 既是一份变更清单,也是一份浓缩的架构设计文档——结合 Sources 阅读,能比单纯追版本号获得更多可复用的转场实现经验。
【免费下载链接】HeroElegant transition library for iOS & tvOS项目地址: https://gitcode.com/gh_mirrors/he/Hero
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考