0Pricing
Swift Academy · 课时

自定义 AnimatableModifier 与 Animatable

使自定义绘制内容遵循 Animatable 和 AnimatableModifier,从而为其添加动画。

自定义 AnimatableModifier 与 Animatable 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

Animatable 协议

Animatable 用于告诉 SwiftUI 如何在动画过程中对某个类型进行插值。形状会自动遵循该协议。

struct Wave: Shape, Animatable {
  var amplitude: Double
  var animatableData: Double {
    get { amplitude }
    set { amplitude = newValue }
  }
  func path(in rect: CGRect) -> Path { Path() }
}

animatableData 属性

SwiftUI 会在每个动画帧读取和写入 animatableData,以便在起始值和结束值之间进行插值。

struct GrowingCircle: Shape {
  var radius: Double
  var animatableData: Double {
    get { radius }
    set { radius = newValue }
  }
  func path(in rect: CGRect) -> Path {
    Path(ellipseIn: CGRect(x: rect.midX-radius, y: rect.midY-radius, width: radius*2, height: radius*2))
  }
}

使用 AnimatablePair 处理多个值

使用 AnimatablePair 可以同时为两个相互独立的值添加动画。

struct Sector: Shape {
  var startAngle: Double, endAngle: Double
  var animatableData: AnimatablePair<Double, Double> {
    get { AnimatablePair(startAngle, endAngle) }
    set { startAngle = newValue.first; endAngle = newValue.second }
  }
  func path(in rect: CGRect) -> Path { Path() }
}

ViewModifier + Animatable

让 ViewModifier 遵循 Animatable,即可为任意视觉效果添加动画。

struct Shake: ViewModifier, Animatable {
  var animatableData: Double = 0
  func body(content: Content) -> some View {
    content.offset(x: sin(animatableData * .pi * 4) * 8)
  }
}

驱动动画

在 withAnimation 中更改可动画值,SwiftUI 就会通过 animatableData 进行插值。

struct ShakeView: View {
  @State private var shakes = 0.0
  var body: some View {
    Text("Hello")
      .modifier(Shake(animatableData: shakes))
      .onTapGesture {
        withAnimation(.linear(duration: 0.5)) { shakes += 1 }
      }
  }
}

AnimatableModifier(已弃用)与 Animatable + ViewModifier

AnimatableModifier 已在较新的 SDK 中弃用。建议直接让您的 ViewModifier 遵循 Animatable。

// Modern approach:
struct MyMod: ViewModifier, Animatable { ... }
// Avoid (deprecated):
// struct MyMod: AnimatableModifier { ... }

将自定义数值类型用作 animatableData

任何遵循 VectorArithmetic 的类型都可以用作 animatableData。Swift 的 CGFloat、Double 和 AnimatablePair 都符合要求。

extension MyColor: VectorArithmetic {
  static func += (lhs: inout MyColor, rhs: MyColor) { ... }
  mutating func scale(by rhs: Double) { ... }
  var magnitudeSquared: Double { ... }
}

基于进度的修饰器

一种常见模式是:将 progress 值从 0 动画到 1,然后在修饰器内部计算视觉属性。

struct FillModifier: ViewModifier, Animatable {
  var progress: Double
  var animatableData: Double { get { progress } set { progress = newValue } }
  func body(content: Content) -> some View {
    content.overlay(Color.blue.opacity(progress))
  }
}

与 .animation 链式组合

附加动画后,状态变化会自动驱动可动画修饰器的进度值。

Text("Loading")
  .modifier(FillModifier(progress: isLoaded ? 1 : 0))
  .animation(.easeInOut(duration: 1.0), value: isLoaded)

为自定义形状添加动画

最强大的用法是:通过 animatableData 对控制点进行插值,在两个路径形状之间实现变形。

struct Blob: Shape, Animatable {
  var bulge: Double
  var animatableData: Double { get { bulge } set { bulge = newValue } }
  func path(in rect: CGRect) -> Path {
    // compute bezier with bulge-adjusted control points
    Path()
  }
}

性能

SwiftUI 会在每个动画帧调用修饰器的 body。请尽量减少 body 内的计算,以确保流畅运行在 60/120 帧每秒。

// OK: simple math in body
// AVOID: network calls, heavy computation in animated body

快速检查

SwiftUI 会在每个动画帧读取和写入什么内容,以便对自定义可动画类型进行插值?

课程回顾

让形状或视图修饰器遵循 Animatable,并公开 animatableData(一个 VectorArithmetic 值)。SwiftUI 会在每个帧中对其进行插值。对于两个值,请使用 AnimatablePair。使用 withAnimation 或 .animation 驱动动画。

常见问题解答

「自定义 AnimatableModifier 与 Animatable」课时是免费的吗?

是的 — 「自定义 AnimatableModifier 与 Animatable」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「自定义 AnimatableModifier 与 Animatable」这节课中我会学到什么?

使自定义绘制内容遵循 Animatable 和 AnimatableModifier,从而为其添加动画。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「自定义 AnimatableModifier 与 Animatable」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 隐式动画与显式动画
  2. 使用 matchedGeometryEffect 实现英雄转场
  3. 自定义 AnimatableModifier 与 Animatable
  4. TimelineView 与 Canvas 高性能绘制
← 返回 Swift Academy