SwiftUI 已经简化了视图动画的创建。一个例子是 matchedGeometryEffect
modifier,它使开发人员能够定义两个视图的外观。modifier 计算两个视图之间的差异,并自动为大小和位置变化设置动画。在 iOS 17 中,Apple 继续改进 SwiftUI 框架,并提供了一种名为 PhaseAnimator
,这使我们能够制作更复杂的动画。
在本教程中,我们将探索 PhaseAnimator
并学习如何利用它来创建多步骤动画。
使用 PhaseAnimator 构建简单动画
这 PhaseAnimator
视图,或 .phaseAnimator
修改器,使您能够生成多步骤动画。通过循环您提供的一系列阶段(每个阶段代表一个不同的步骤),您可以创建动态且引人入胜的动画。

让我举一个简单的例子,这样你就会明白如何使用相位动画器。我们将为圆角矩形的变换制作动画。它一开始是一个蓝色矩形,然后放大,颜色变为靛蓝色,并包含 3D 旋转动画。
我们可以使用 RoundedRectangle
视图创建圆角矩形并附加 phaseAnimator
像这样对矩形进行修改:
struct ContentView: View {
var body: some View {
RoundedRectangle(cornerRadius: 25.0)
.frame(height: 200)
.phaseAnimator([ false, true ]) { content, phase in
content
.scaleEffect(phase ? 1.0 : 0.5)
.foregroundStyle(phase ? .indigo : .blue)
}
}
}
在阶段动画器中,我们指定两个阶段: false
和 true
。视图构建器闭包接受两个参数。第一个参数是一个代理值,表示修改后的视图。第二个参数表示当前阶段。
当视图最初出现时,第一阶段(即 false
) 处于活动状态。我们将比例设置为原始大小的 50%,并将前景色设置为蓝色。在第二阶段,矩形将缩小回其原始大小,颜色过渡为靛蓝。
阶段动画器自动为这两个阶段之间的变化制作动画。

要创建 3D 旋转动画,您可以附加 rotation3DEffect
修饰符 content
如下图所示:
.rotation3DEffect(
phase ? .degrees(720) : .zero,
axis: (x: 0.0, y: 1.0, z: 0.0)
)
如果你想自定义动画, phaseAnimator
还提供了 animation
参数用于定义您喜欢的动画。根据给定的阶段,您可以指定从一个阶段移动到另一个阶段时要使用的动画。以下是示例:
.phaseAnimator([ false, true ]) { content, phase in
content
.scaleEffect(phase ? 1.0 : 0.5)
.foregroundStyle(phase ? .indigo : .blue)
.rotation3DEffect(
phase ? .degrees(720) : .zero,
axis: (x: 0.0, y: 1.0, z: 0.0)
)
} animation: { phase in
switch phase {
case true: .smooth.speed(0.2)
case false: .spring
}
}
使用枚举定义多步骤动画
在前面的例子中,动画仅包含两个阶段: false
和 true
。然而,在更复杂的动画中,通常会涉及多个步骤或阶段。在这种情况下,枚举是定义动画步骤列表的好方法。

让我们考虑一个表情符号图标动画的示例,其步骤如下:
- 最初,表情符号图标位于屏幕的中心。
- 它放大了 50% 并旋转了 720 度。
- 接下来,它向上移动 250 个点,同时向下缩减 20%。
- 然后,它向下移动 450 点。下降过程中,它自身旋转 360 度,并缩小 50%。
- 最后它又回到原来的位置。
通过这些步骤,我们可以为表情符号图标创建动态动画。
为了实现这个多步骤动画,我们可以定义一个这样的枚举:
enum Phase: CaseIterable {
case initial
case rotate
case jump
case fall
var scale: Double {
switch self {
case .initial: 1.0
case .rotate: 1.5
case .jump: 0.8
case .fall: 0.5
}
}
var angle: Angle {
switch self {
case .initial, .jump: Angle(degrees: 0)
case .rotate: Angle(degrees: 720)
case .fall: Angle(degrees: 360)
}
}
var offset: Double {
switch self {
case .initial, .rotate: 0
case .jump: -250.0
case .fall: 450.0
}
}
}
在此枚举中,我们有四种情况,代表动画的不同步骤。在每个阶段,我们对表情符号图标执行缩放、旋转或移动。为此,我们为每个操作定义三个计算属性。在每个属性中,我们为特定动画阶段或步骤指定值。
例如,在“旋转”阶段,表情符号应放大 50% 并旋转 720 度。 scale
属性返回 1.5,并且 angle
财产回报 Angle(degrees: 720)
。
随着 Phase
枚举,我们现在可以使用阶段动画器轻松地为表情符号制作动画,如下所示:
Text("🐻")
.font(.system(size: 100))
.phaseAnimator(Phase.allCases) { content, phase in
content
.scaleEffect(phase.scale)
.rotationEffect(phase.angle)
.offset(y: phase.offset)
} animation: { phase in
switch phase {
case .initial: .bouncy
case .rotate: .smooth
case .jump: .snappy
case .fall: .interactiveSpring
}
}
这 Phase.allCases
自动通知阶段动画器可用的阶段。根据给定的阶段,表情符号图标将根据计算值进行缩放、旋转和移动。
为了定制动画,我们可以指定特定的动画,例如 snappy
,针对不同阶段,而不是使用默认动画。
使用触发器
目前,阶段动画器会自动启动动画并无限重复。但是,在某些情况下,您可能希望手动触发动画。在这种情况下,您可以通过在 trigger
相位动画器的参数。
例如,当用户点击表情符号时,应触发表情符号动画。您可以先声明一个状态变量,如下所示:
@State private var startAnimation = false
接下来,更新 phaseAnimator
通过添加修饰符 trigger
范围:
.phaseAnimator(Phase.allCases, trigger: startAnimation, content: { content, phase in
content
.scaleEffect(phase.scale)
.rotationEffect(phase.angle)
.offset(y: phase.offset)
}, animation: { phase in
switch phase {
case .initial: .bouncy
case .rotate: .smooth
case .jump: .snappy
case .fall: .interactiveSpring
}
})
修改代码后,动画只会在以下情况下触发: startAnimation
从 false
到 true
。为此,请将 onTapGesture
文本视图的修饰符。
.onTapGesture {
startAnimation.toggle()
}
当用户点击表情符号时,我们会切换 startAnimation
.这将触发多步骤动画。
概括
引入 PhaseAnimator
使创建多步骤动画的过程变得非常简单。通过使用枚举来定义动画的每个步骤应发生哪些变化,您只需几行代码即可创建动态且引人入胜的动画。SwiftUI 的 PhaseAnimator
以及其他有用的功能,为您完成艰苦的工作,因此开发人员可以专注于制作令人印象深刻的动画而无任何麻烦。
如果您喜欢阅读本教程,您可以继续阅读我们的《掌握 SwiftUI》一书,以了解有关 SwiftUI 框架的更多信息。