除了 PhaseAnimator
,SwiftUI 在 iOS 17 中還引入了 KeyframeAnimator
,允許開發者使用關鍵幀(keyframe)建立更進階動畫。在本教程中,我們將深入研究 KeyframeAnimator
,並學習如何創建更複雜的動畫。
我們在前一個教學中討論的 PhaseAnimator
視圖(或修飾器)為開發者提供了在一系列相位中創建多步驟動畫的能力。通過為每個相位指定所需的動畫,PhaseAnimator
在相位變化時自動對內容進行動畫處理。它通過為你處理相位之間的過渡,簡化了構建複雜動畫的過程。
對於階段性的動畫(Phase-based Animation),它適用於可以表示為離散狀態的動畫。當狀態轉換發生時,所有屬性都同時進行動畫。一旦特定狀態的動畫完成,SwiftUI 將平滑地過渡到下一個狀態。這個過程會應用到所有動畫階段中。
基於關鍵幀的動畫(Keyframe-based animation)旨在應對一種特定類型的動畫,其中每個屬性都可以獨立進行動畫化。通過利用關鍵幀,我們可以分別對個別的屬性建立動畫,從而為我們的動畫提供更大的靈活性和控制能力。
讓我們嘗試對一個表情符號圖標進行動畫(如上所示),你將理解我們如何使用關鍵幀動畫器(keyframe animator)。
如前所述,基於關鍵幀的動畫使我們能夠獨立地對個別的屬性進行動畫。為了利用關鍵幀動畫器,我們首先定義一個結構,該結構包含我們希望進行動畫的所有屬性。以下是一個示例:
struct AnimationValues {
var scale = 1.0
var verticalStretch = 1.0
var translation = CGSize.zero
var opacity = 1.0
}
初始值定義了表情符號圖標的初始狀態。稍後,我們將更改每個屬性以縮放、拉伸和移動表情符號圖標。
在 body
閉包中,讓我們更新代碼,以應用關鍵幀動畫器:
Text("🐻")
.font(.system(size: 100))
.keyframeAnimator(initialValue: AnimationValues()) {
content, value in
content
.scaleEffect(value.scale)
.scaleEffect(y: value.verticalStretch)
.offset(value.translation)
.opacity(value.opacity)
} keyframes: { _ in
KeyframeTrack(\.scale) {
CubicKeyframe(0.8, duration: 0.2)
}
}
像往常一樣,我們使用 Text
視圖來顯示表情符號圖標。要創建基於關鍵幀的動畫,我們將 keyframeAnimator
修飾器附加到文本視圖上。
initialValue
參數提供了關鍵幀將從中進行動畫的初始值。在視圖構建器閉包內,我們可以訪問兩個參數。第一個參數是代表修改後的視圖的代理值。第二個參數保存了關鍵幀生成的插值值。
我們通過調整視圖的縮放、偏移和不透明度來應用所需的動畫效果。最後是 keyframes
參數。在這裡,我們定義隨時間變化的值。這些定義的關鍵幀將負責對指定的值應用相應的動畫。
關鍵幀按照軌道排列,每個軌道控制動畫類型的不同屬性。在提供的程式碼片段中,我們使用 CubicKeyframe
類型特別指定了縮放屬性的關鍵幀軌道。我們調整表情符號的大小,將其縮小到原始大小的80%。
一旦你修改程式碼之後,你應該能夠立即在預覽畫布中看到動畫效果。關鍵幀動畫器將對大小變化進行動畫處理並且不斷重複。
雖然我們使用了 CubicKeyframe
類型,但實際上有四種不同的關鍵幀類型可供使用:
LinearKeyframe
- 在向量空間中從前一個關鍵幀線性插值。SpringKeyframe
- 使用彈簧函數從前一個關鍵幀插值到目標值。CubicKeyframe
- 使用三次貝塞爾曲線(cubic Bézier curve)在關鍵幀之間進行插值。MoveKeyframe
- 立即跳至一個值,不進行插值。嘗試探索和測試不同的關鍵幀類型和持續時間,觀察它們的行為。通過嘗試不同的關鍵幀類型和調整持續時間,你可以更深入地了解它們對動畫的影響和塑造方式。
目前,我們只對 scale
屬性應用了單一變化。你可以自由定義隨時間變化的其他值。以下是一個示例:
KeyframeTrack(\.scale) {
CubicKeyframe(0.8, duration: 0.2)
CubicKeyframe(0.6, duration: 0.3)
CubicKeyframe(1.0, duration: 0.3)
CubicKeyframe(0.8, duration: 0.2)
CubicKeyframe(0.6, duration: 0.3)
CubicKeyframe(1.0, duration: 0.3)
}
The code describes the scale factor at specific times within the animation. In the preview canvas, you'll notice a smoother and more fluid animation for the emoji icon.
到目前為止,我們專注於單個關鍵幀軌道來改變比例因子。然而,通過定義獨立的軌道,每個軌道具有自己獨特的定時,關鍵幀提供了獨立地動畫多個效果的能力。通過結合多個軌道,我們可以同時動畫各種屬性,從而創建更高級的動畫。
在同一個示例中,我們可以為垂直拉伸、平移和不透明度屬性定義獨立的關鍵幀軌道。以下是示例程式碼:
Text("🐻")
.font(.system(size: 100))
.keyframeAnimator(initialValue: AnimationValues()) { content, value in
content
.scaleEffect(value.scale)
.scaleEffect(y: value.verticalStretch)
.offset(value.translation)
.opacity(value.opacity)
} keyframes: { _ in
KeyframeTrack(\.verticalStretch) {
LinearKeyframe(1.2, duration: 0.1)
SpringKeyframe(2.0, duration: 0.2, spring: .snappy)
CubicKeyframe(1.05, duration: 0.3)
CubicKeyframe(1.2, duration: 0.2)
CubicKeyframe(1.1, duration: 0.32)
CubicKeyframe(1.2, duration: 0.2)
CubicKeyframe(1.05, duration: 0.25)
CubicKeyframe(1.3, duration: 0.23)
CubicKeyframe(1.0, duration: 0.3)
}
KeyframeTrack(\.scale) {
CubicKeyframe(0.8, duration: 0.2)
CubicKeyframe(0.6, duration: 0.3)
CubicKeyframe(1.0, duration: 0.3)
CubicKeyframe(0.8, duration: 0.2)
CubicKeyframe(0.6, duration: 0.3)
CubicKeyframe(1.0, duration: 0.3)
}
KeyframeTrack(\.translation) {
SpringKeyframe(CGSize(width: 100, height: 100), duration: 0.4)
SpringKeyframe(CGSize(width: -50, height: -300), duration: 0.4)
SpringKeyframe(.zero, duration: 0.2)
SpringKeyframe(CGSize(width: -50, height: 200), duration: 0.3)
SpringKeyframe(CGSize(width: -90, height: 300), duration: 0.3)
SpringKeyframe(.zero, duration: 0.4)
}
KeyframeTrack(\.opacity) {
LinearKeyframe(0.5, duration: 0.2)
LinearKeyframe(1.0, duration: 0.23)
LinearKeyframe(0.7, duration: 0.25)
LinearKeyframe(1.0, duration: 0.33)
LinearKeyframe(0.8, duration: 0.2)
LinearKeyframe(1.0, duration: 0.23)
}
}
通過使用多個關鍵幀軌道,我們可以實現一個有趣的動畫效果。在這種情況下,表情符號圖標將在隨機位置移動,同時其不透明度在特定時間點變化。
在預設的情況下,關鍵幀動畫器會持續執行動畫。如果你想停止動畫,可以將 repeat
參數設置為 false
。
你可以使用 ZStack
和重疊另一個表情符號圖標來創建如下所示的動畫效果。我將將這作為一個練習,讓你自行探索和實現。
KeyframeAnimator
是引入到 iOS 17 中的一個寶貴功能。與 PhaseAnimator
修飾符相比,這個在 SwiftUI 中的新工具使開發者能夠使用關鍵幀創建高級動畫。
通過利用關鍵幀,開發者可以在時間軸上定義特定的時間點並精確地操作動畫的屬性。這種增強的控制力使得可以創建複雜而動態的視覺效果,從而實現更流暢的動畫。
你可以在這裡下載示例項目以供參考: