SwiftUI已經簡化了視圖動畫的創建。其中一個例子是 matchedGeometryEffect
修飾器,它使開發者能夠定義兩個視圖的外觀。該修飾符計算兩個視圖之間的差異並自動動畫化大小和位置的變化。在iOS 17中,蘋果在SwiftUI框架中繼續改進了一個名為 PhaseAnimator
的新視圖,使我們能夠創建更複雜的動畫。
在本教學中,我們將探索 PhaseAnimator
的能力,並學習如何利用它來創建多步驟(Multi-step)的動畫。
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)
}
}
}
在 phaseAnimator
中,我們指定了兩個階段: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
。然而,在更複雜的動畫中,通常涉及多個步驟或相位。在這種情況下,使用枚舉是一種很好的方式來定義動畫的步驟列表。
讓我們看看一個例子,動畫一個表情符號圖標,包含以下步驟:
有了這些步驟,我們可以為表情符號圖標創建一個動態動畫。
要實現這個多步驟動畫,我們可以像這樣定義一個枚舉:
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
接下來,你通過添加 trigger
參數來更新 phaseAnimator
修飾器:
.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
修飾器附加到 Text 視圖上即可。
.onTapGesture {
startAnimation.toggle()
}
當使用者點擊表情符號時,我們切換 startAnimation
的值。這將觸發多步驟動畫。
引入 PhaseAnimator
大大簡化了創建多步驟動畫的過程。通過使用枚舉來定義動畫的每個步驟應該發生的變化,你只需幾行程式碼就可以創建出動態而引人入勝的動畫效果。SwiftUI 的 PhaseAnimator
與其他有用的功能一起,為你處理了繁重的工作,讓開發者能夠專注於創建令人印象深刻的動畫,而無需煩惱任何麻煩事。
您可以在此處下載演示項目作為參考: