关于 ios-animation-implementation
面向 iOS 开发者的动画实现技能,指导使用 Apple 框架编写动画。内容涵盖 API 选择、辅助功能、可中断性和性能,并按任务提供参考文件。
主要功能
- 01动画 API 选择指导
- 02SwiftUI、UIKit 与 Core Animation 模式
- 03减少动态效果与反馈指导
- 04可中断性和性能检查
- 05按任务分类的动画参考
适用场景
- 01为自定义转场选择 API
- 02添加手势驱动动画
- 03支持减少动态效果设置
- 04检查动画性能风险
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ existential-birds/ beagle --skill ios-animation-implementation安装后在 Claude Code 中输入/ios-animation-implementation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/core-animation.mdgesture-animations.mdswiftui-animations.mdtransitions.md详细介绍
iOS 动画实现
编写直接使用 Apple 框架的动画代码。第三方动画库会增加依赖风险,而且往往落后于新的 OS 版本;Apple 的 API 针对渲染管线进行了充分优化,并且每个 iOS 版本都会带来免费改进。
编写自定义动画之前
先检查系统是否已经处理了你需要的动效。Apple 的 HIG 指出:“许多系统组件都自动包含动效,让你能在整个 App 中提供熟悉且一致的体验。”系统组件还会自动根据辅助功能设置和输入方式进行调整——Liquid Glass(iOS 26)对直接触控的反馈更明显,而对触控板则会产生较柔和的效果。自定义动画无法免费获得这种适应性,因此系统提供了动效时,优先使用系统动效。
以下情况跳过自定义动画:
- 标准导航转场已能满足需求(push、pop、sheet、fullScreenCover)
- SF Symbol 的
.symbolEffect已能提供所需反馈 .contentTransition(.numericText)已能处理数据变化withAnimation的系统默认弹簧效果已足够
以下情况编写自定义动画:
- 系统未提供所需的空间关系(英雄转场、自定义手势)
- 需要协调多个属性的编排
- 动画是定义 App 特征的标志性时刻
- 手势驱动的交互需要自定义进度映射
API 选择
根据需求选择合适的 API。从 SwiftUI 动画(最简单、声明性最强)开始,需要交互控制时再使用 UIKit,只有需要图层级精度时才使用 Core Animation。
| 需求 | API | 原因 |
|---|---|---|
| 状态驱动的属性变化 | withAnimation / .animation(_:value:) | 声明式、自动插值 |
| 多步骤序列动画 | PhaseAnimator | 离散阶段,可为每个阶段单独设置时长 |
| 按属性控制时间线 | KeyframeAnimator | 每个属性都有独立的关键帧轨道 |
| 视图间的英雄转场 | matchedGeometryEffect + Namespace | 跨视图身份匹配几何形状 |
| 带缩放效果的导航 push/pop | .navigationTransition(.zoom) | iOS 18+ 内置缩放转场 |
| 自定义视图插入/移除 | 遵循 Transition 协议 | 基于 TransitionPhase 的修饰符 |
| 视图内内容切换 | .contentTransition() | 数字文本、插值、不透明度 |
| 基于滚动位置的效果 | .scrollTransition | 由阶段驱动的滚动联动动画 |
| SF Symbol 动画 | .symbolEffect() | 弹跳、脉冲、摆动、呼吸、旋转 |
| 交互式/可中断动画(UIKit) | UIViewPropertyAnimator | 暂停、继续、反转、拖动进度 |
| 按图层设置属性动画 | CABasicAnimation / CASpringAnimation | 阴影、边框、cornerRadius 动画 |
| 复杂动画编排(图层) | CAKeyframeAnimation + CAAnimationGroup | 多属性图层动画 |
| 物理模拟 | UIDynamicAnimator | 重力、碰撞、吸附、连接 |
| 与动画配套的触觉反馈 | .sensoryFeedback 修饰符 | 与值变化关联 |
| 动画背景渐变 | MeshGradient | 由定位并动态变化的颜色组成的二维网格 |
按类别实现
详细模式和代码示例位于参考文件中。加载与你的任务相符的文件:
| 任务 | 参考 |
|---|---|
| SwiftUI 声明式动画(withAnimation、弹簧、阶段、关键帧) | references/swiftui-animations.md |
| 视图转场(导航、模态、自定义 Transition 协议) | references/transitions.md |
| 手势驱动的交互式动画 | references/gesture-animations.md |
| Core Animation 和 UIKit 动画模式 | references/core-animation.md |
何时加载参考资料
- 编写
withAnimation、弹簧参数、PhaseAnimator或KeyframeAnimator→ swiftui-animations.md - 构建导航转场、模态呈现、
matchedGeometryEffect或自定义Transition→ transitions.md - 实现拖动关闭、滑动操作、捏合/旋转或滚动联动效果 → gesture-animations.md
- 使用
CABasicAnimation、UIViewPropertyAnimator、图层动画,或桥接 SwiftUI↔UIKit → core-animation.md
弹簧参数速查
弹簧是现代 SwiftUI 中默认的动画类型。使用 duration 和 bounce,不要使用质量/刚度/阻尼参数,除非要桥接到 UIKit/CA。
| 预设 | 时长 | 弹跳 | 用例 |
|---|---|---|---|
.smooth | 0.5 | 0.0 | 默认转场、大多数状态变化 |
.snappy | 0.3 | 0.15 | 微交互、切换控件、快速反馈 |
.bouncy | 0.5 | 0.3 | 俏皮时刻、吸引注意力 |
.interactiveSpring | 0.15 | 0.0 | 手势跟踪、跟随拖动 |
| 自定义 | 不定 | 不定 | .spring(duration: 0.4, bounce: 0.2) |
无障碍与多模态反馈
Apple 的 HIG:“让动态效果可选”,并“通过触觉和音频等替代方式补充视觉反馈,以传达信息”。每个动画都必须处理减少动态效果设置,重要的状态变化应使用多种反馈渠道,而不能只依赖动画。
@Environment(\.accessibilityReduceMotion) private var reduceMotion
// Pattern 1: Conditional animation
withAnimation(reduceMotion ? .none : .spring()) {
isExpanded.toggle()
}
// Pattern 2: Simplified alternative
.animation(reduceMotion ? .easeOut(duration: 0.15) : .spring(duration: 0.5, bounce: 0.3), value: isActive)
// Pattern 3: Skip entirely
if !reduceMotion {
view.phaseAnimator(phases) { /* ... */ }
}
减少动态效果时的替代选项(从最自然到最直接):
- 交叉淡化 — 用不透明度转场替代动态效果
- 缩短时长 — 保持相同动画,但显著加快(0.1–0.15s),不添加弹跳
- 即时切换 — 使用
.animation(.none)或完全跳过动画代码块
取消与可中断性
Apple 的 HIG:“不要让人们必须等待动画播放完毕才能进行任何操作,尤其是他们需要多次体验该动画时。”每个动画都必须可中断。
- 弹簧动画会自动调整目标值——这是默认行为,几乎总是你想要的效果
- 对于手势驱动的动画,始终由用户掌控——允许他们在动画进行中取消
- 对于按序播放的动画(KeyframeAnimator、带触发器的 PhaseAnimator),确保播放期间 UI 仍可交互
- 除非有关键原因(例如确认破坏性操作),否则不要在动画期间禁用用户交互
性能检查清单
- 尽可能在渲染服务端运行动画——Core Animation 在主线程之外运行,SwiftUI 的
drawingGroup()会将渲染转移到 Metal - 避免为视图标识变化设置动画(
.id()修饰符)——这会销毁并重新创建视图 - 当父视图几何变化导致子视图布局在动画期间出现异常时,使用
geometryGroup() - 为阴影动画提供显式的
shadowPath——否则系统会在每一帧重新计算路径 - 在列表和滚动视图中,避免为每个项目添加模糊/阴影动画——这会导致每个单元格都进行屏幕外渲染
- 保持
PhaseAnimator和循环动画轻量——它们会持续运行 - 对于频繁交互,优先使用系统提供的动画,而非自定义动态效果——Apple 的 HIG:“通常应避免为频繁发生的 UI 交互添加动态效果”
- 使用 Instruments →“Animation Hitches”模板分析,找出帧丢失问题
门禁(标记工作完成前)
按顺序运行;满足每项通过条件后,才能将任务视为完成。
- API 匹配 — 根据此任务,从 API 选择表中选择机制。**通过:**你可以用一句话说明应用了哪一行“需求”和哪个 API,而不是“仅仅因为”想用不同层级。
- 减少动态效果 — 自定义时序必须遵循“无障碍与多模态反馈”。**通过:**非平凡动态效果会根据
accessibilityReduceMotion分支处理(或者你只使用系统默认设置/未使用自定义时序)。 - 可中断性 — 符合“取消与可中断性”。**通过:**没有对整个动画一概使用
allowsHitTesting(false),除非任务明确要求这样做,并且有简短注释说明原因。 - 高负载或连续动态效果 — 循环、始终开启的
PhaseAnimator、逐单元格模糊/阴影,或其他性能检查清单中的警示项。**通过:**你运行了 Instruments(Animation Hitches)并记录了说明或追踪文件路径,或者你先简化了这种模式,并能指出所做的更改。