SwiftUI Motion 是一份面向 SwiftUI 动画核心的知识技能包,适用于任何 SwiftUI 项目(iOS、macOS 及多目标 Apple 平台)。文档在此处只给出简明规则,深入内容放在 references/ 目录中,并建议与 ../motion-principles/SKILL.md(基础)和 ../mobile-principles/SKILL.md(触摸 UX)配合使用。
一、动画 API 决策树 文档提供了一张按需求选择 API 的对照表:
- 单值随时间变化:withAnimation { } 配合 @State,或 .animation(_, value:)。
- 多个协调状态:PhaseAnimator(phases)(iOS 17+)。
- 基于时间的关键帧:KeyframeAnimator(initialValue:repeating:content:)(iOS 17+)。
- 自定义属性动画:@Animatable 宏(iOS 26+)或 Animatable 协议(iOS 13+)。
- 共享元素过渡:matchedGeometryEffect(id:in:)。
- 手势驱动:DragGesture / MagnifyGesture 配合 .offset / .scaleEffect。
- 永久循环:.animation(.linear.repeatForever(autoreverses: true), value: ...) 或 .phaseAnimator。 规则是:优先从 withAnimation 开始;只有当存在 3 个以上有序状态时才使用 PhaseAnimator;只有当需要并行的时间轨道时才使用 KeyframeAnimator。
二、弹簧动画 文档指出 SwiftUI 在 iOS 17+ 内置 4 种具名弹簧,建议优先使用它们,仅在预设不符合需求时才调整 response / dampingFraction:.snappy、.bouncy、.smooth、.interactiveSpring()。response 是弹簧稳定所需时间(越低越干脆,越高越柔和),dampingFraction 是 0...1 的过冲强度(1 表示无过冲,0 表示永久振荡,永不使用 0)。UI 工作中建议保持 response 在 0.2...0.5、dampingFraction 在 0.7...1.0。iOS 17+ 还提供 .spring(duration:bounce:),其中 bounce 为 0...1,是同一弹簧更面向设计者的表达方式。
三、隐式与显式动画 文档给出两种写法:隐式通过 .animation 修饰符绑定某个值;显式通过 withAnimation 代码块。规则是:用户操作触发的状态变化优先使用显式 withAnimation;当某个值的任何变化都应始终动画时使用隐式。不要在同一属性上同时使用两者。
四、过渡 过渡驱动 if、switch 或 ForEach 中视图的插入与移除,在父级动画上下文触发时运行,因此状态变更需包裹在 withAnimation 中。文档给出使用 .asymmetric 组合 insertion 与 removal 的示例;并指出 .scale 缩小到 0 是“消失进黑洞”的坏做法,应改用 .scale(scale: 0.95).combined(with: .opacity)。iOS 17+ 还提供带自定义 Transition 协议的 .transition(_:) 修饰符。
五、matchedGeometryEffect(英雄动画) 在同一 Namespace 中为两个视图打上相同 id,SwiftUI 会在源视图被替换时插值 frame 与 position。文档给出画廊示例代码,并提示常见陷阱:不相关命名空间之间的 id 冲突、视图身份不稳定(应使用稳定 id 而非数组索引)、以及从 if 分支动画到尚不存在的目标视图。
六、PhaseAnimator(iOS 17+) 用于有序状态编排。定义 CaseIterable + Hashable 枚举,SwiftUI 依次走过各阶段并停在最后一个上。文档给出成功打勾动画的示例。trigger 为可选参数,省略时在出现后自动推进各阶段。各阶段顺序执行,从不并行;如需并行应使用 KeyframeAnimator。
七、KeyframeAnimator(iOS 17+) 用于带并行轨道的连续时间动画。每个 KeyframeTrack 独立动画一个 keypath,SwiftUI 同时运行它们。文档给出爱心点击示例,说明四种关键帧类型:LinearKeyframe(点间匀速)、SpringKeyframe(带弹簧稳定)、CubicKeyframe(三次贝塞尔缓动)、MoveKeyframe(跳切、无插值)。在值变化时触发可重跑动画。
八、Animatable / @Animatable 用于需要插值的自定义绘制。@Animatable 宏(iOS 26+,WWDC25)可为任意 Equatable 属性自动合成 animatableData;较旧的 Animatable 协议(iOS 13+)在 26 之前仍可用。文档给出 ProgressRing 形状示例,并说明多属性形状应使用 AnimatablePair<A, B>(或嵌套对)。
九、手势 文档列出常见手势及类型与用途:TapGesture(离散,点击、双击 count: 2)、LongPressGesture(离散 + 连续)、DragGesture(连续,拖拽、滑动关闭)、MagnifyGesture(连续,捏合缩放,iOS 17+ 替代 MagnificationGesture)、RotateGesture(连续,旋转,iOS 17+)、SpatialTapGesture(离散,带位置信息)。三种组合操作符:.simultaneously(with:)(并行识别)、.sequenced(before:)(须先完成其一)、.exclusively(before:)(二选一)。如需精细控制子视图何时能声明手势,可使用 .simultaneousGesture(_, including: GestureMask)。
十、反模式(BAD / GOOD) 文档列出四类反模式及改进方式:1)已废弃的不带 value 绑定的 .animation 形式;2)直接动画 frame 尺寸(应改为动画 transform 等价的 scale、offset,或使用 matchedGeometryEffect);3)缩放到 0;4)在 body 内使用 withAnimation。
十一、尊重减弱动态效果 文档强调这是强制要求。SwiftUI 通过环境暴露 iOS / macOS 的“减弱动态效果”辅助功能设置。跨平台理由见 ../motion-principles/SKILL.md。规则是:在减弱动态效果下仍允许交叉淡入淡出和透明度;大位移、从零缩放、视差和循环运动必须被中和。
十二、快速参考:加载子技能 文档给出按需求加载子技能文件的对照表,包括弹簧深入、PhaseAnimator 与 KeyframeAnimator 复杂序列、手势组合与冲突解决、高级视觉(Metal、Liquid Glass)、跨平台 UX、以及基础(时间、缓动、无障碍)。
文档末尾列出来源:twostraws/SwiftUI-Agent-Skill、GetStream/swiftui-spring-animations、amosgyamfi/open-swiftui-animations、AvdLee/SwiftUI-Agent-Skill、Apple SwiftUI Animations、Apple PhaseAnimator、Apple KeyframeAnimator、WWDC23 Animate with springs、WWDC23 Wind your way through advanced animations。
限制:文档未说明该技能包的收费、价格、具体安装步骤或与其他工具集成的操作方式,这些信息暂未提供。