SuperAPI AI 工具集

swiftui-animations

前端与建站

查看项目

更新于 10-16 02:01

技能介绍

用途

该技能用于在构建、调试或优化 SwiftUI iOS/macOS 应用动画时提供指导,目标是帮助开发者创建流畅、高性能且无障碍友好的动画,并遵循 Apple 的最佳实践。

核心原理

  • 动画由状态变化驱动:SwiftUI 动画的是新旧状态之间的差异。
  • 事务向下传播:用 withAnimation 包裹状态变化时,事务会沿视图层级传播。
  • 只有可动画数据才会动画:类型需符合 Animatable(多数内建类型如 CGFloat、Color、CGSize 已符合)。
  • 动画是声明式的:你描述最终状态,SwiftUI 负责插值。

心理模型:状态变化 → 创建事务 → 视图差分 → 可动画属性插值 → 渲染帧。把动画理解为视图两个快照之间的自动插值,你的工作是:清晰定义两个状态、告诉 SwiftUI 使用哪种时间曲线、确保要动画的属性是 Animatable。

主要能力

隐式动画

  • withAnimation:包裹状态变化,使由此产生的所有视图更新都带动画;适用于你掌控状态变化的场景(按钮点击、手势、响应)。
  • .animation() 修饰符:当被观察的值变化时触发动画;适用于状态变化不受你控制的场景(绑定、父级状态)。资料强调必须始终使用 value: 参数,不带 value 的旧写法已废弃且行为不可预测。

时间曲线

资料列出 .linear(机械恒定运动,如进度条)、.easeIn、.easeOut、.easeInOut、.spring(duration:bounce:)、.spring(response:dampingFraction:)、.interactiveSpring,并建议除非有理由,否则默认使用 .spring()。

显式动画

  • Animatable 协议:类型提供 animatableData 属性即可动画,SwiftUI 会用新旧状态之间的插值值反复调用 setter。
  • AnimatableModifier:用于可复用的动画效果(示例为数字递增叠加显示)。
  • 形状动画:通过 animatableData 动画;多值使用 AnimatablePair,3 个及以上值可嵌套。

过渡

过渡只作用于视图被插入/移除时(通过 if、switch、ForEach 变化)。资料列出内建过渡:.opacity、.slide、.move(edge:)、.scale、.scale(anchor:)、.push(from:)、.offset(x:y:),并说明了组合过渡(.combined)、非对称过渡(.asymmetric)以及基于 ViewModifier 的自定义过渡。关键注意点:过渡需要在添加/移除视图的状态变化外层使用 withAnimation,视图自身的 .animation() 修饰符不会触发过渡。

手势驱动动画

  • 基础拖拽加弹簧回弹:onChanged 中更新 offset,onEnded 中用 withAnimation 归零。
  • @GestureState:手势结束时自动重置,适合临时状态。
  • 速度感知动画:使用手势速度让释放更自然。
  • 跟踪动画进度:使用 GeometryReader + PreferenceKey,或 iOS 17 的 onGeometryChange。
  • 手势弹簧参数建议:拖拽进行中用手势交互弹簧或不加动画;释放回原点用 .spring(response: 0.4, dampingFraction: 0.7);释放到目标用 .spring(response: 0.5, dampingFraction: 0.8);吸附定位用 .spring(response: 0.3, dampingFraction: 0.9)。

iOS 17+ 现代 API

  • PhaseAnimator:自动循环经过离散阶段,适合循环或多步动画;可加 trigger: 参数在值变化时运行而非循环。
  • KeyframeAnimator:对多个属性进行细粒度关键帧控制;关键帧类型包括 LinearKeyframe(恒定速度)、CubicKeyframe(贝塞尔缓动)、SpringKeyframe(基于物理)、MoveKeyframe(瞬间跳转,无插值)。
  • 新弹簧语法:.spring(duration:bounce:),以及预设 .smooth、.snappy、.bouncy。

场景与 API 对照

  • 单次状态变化:withAnimation
  • 循环/周期动画:PhaseAnimator
  • 复杂的多属性编排:KeyframeAnimator
  • 用户触发的序列:带 trigger: 的 PhaseAnimator
  • 精细的时序控制:KeyframeAnimator

关键规则

应当:始终为 .animation() 使用 value:;优先用 withAnimation 而非 .animation();默认使用弹簧动画;尊重减少动态效果(检查 accessibilityReduceMotion);动画布局而非 frame(用 .offset()、.scaleEffect()、.opacity());UI 响应动画保持在 400ms 以内;在真机上测试。

不应当:不要在 body 计算中做动画;不要使用不带 value: 的 .animation();不要与框架对抗;不要同时动画过多属性(最多 2–3 个);不要用 DispatchQueue.main.asyncAfter 做时序编排;不要嵌套 withAnimation 块(最内层生效);不要假设动画完成(SwiftUI 不保证完成回调,关键时序使用 Transaction)。

常见问题排查

资料给出问题—原因—修复的对照:过渡不动画(缺少 withAnimation);动画执行两次(同时用了 withAnimation 和 .animation(),二选一);动画卡顿(动画了非可动画属性,检查类型是否符合 Animatable);弹簧永不停息(dampingFraction 过低,用 0.7+ 或加 .speed());动画作用在错误视图(事务意外传播,用 .transaction { $0.animation = nil } 阻断);列表项动画异常(缺少稳定 id,确保 Identifiable 使用稳定 ID)。

无障碍

用户可在系统设置中开启“减少动态效果”。资料建议通过 @Environment(.accessibilityReduceMotion) 读取该设置,并为过渡与动画提供替代方案(如使用 .opacity 或更短更简单的淡入淡出)。指南包括:淡入淡出总是安全的;减少而非移除动效;避免前庭刺激(大幅缩放、视差、旋转);开启该设置进行测试。

适用场景与限制

适用于 SwiftUI iOS/macOS 应用的动画构建、调试与优化。资料中涉及的具体 API 可用性以对应系统版本为前提(如 iOS 17+ 的 PhaseAnimator、KeyframeAnimator、新弹簧语法与 onGeometryChange)。除资料已述内容外,其余功能、收费、价格、平台、效果或使用步骤暂未提供。