🔴

【iOS】ColorだってKeyFrameでアニメーションさせたい

2024/01/30に公開

iOS 17から追加されたKeyFrameを活用することでそれぞれの値それぞれの時間軸で簡単にアニメーション出来るようになりました。

今回、KeyFrameについての詳細は省きますが興味を持った方はWWDC23のセッションをご覧いただければと思います。

https://developer.apple.com/videos/play/wwdc2023/10157

簡単な例

アニメーションの値を定義

まずはアニメーションに使用する値を定義します。

struct AnimationValues {
    var scale: CGFloat
}

keyframeAnimatorモディファイアを追加

struct CircleView: View {
    var body: some View {
        Circle()
            .frame(width: 10, height: 10)
            .keyframeAnimator(
                initialValue: AnimationValues(scale: 1)
            ) { content, value in
                content
                    .scaleEffect(x: value.scale, y: value.scale)
            } keyframes: { _ in
                
                KeyframeTrack(\.scale) {
                    CubicKeyframe(4, duration: 4)
                    SpringKeyframe(10, duration: 4, spring: .bouncy)
                }
            }
        
    }
}

こちらの実装例では、最初の4秒間でscaleを元サイズの4倍にして、その後、4秒間でscaleを元サイズの10倍にしています。
最後の4秒間では、SpringKeyframeを使用してスプリング関数を用いたアニメーションを実行しています。

demo 1

Colorをアニメーションさせたい

アニメーションの値にColorを追加

struct AnimationValues {
    var scale: CGFloat
+   var color: Color
}

keyframeAnimatorにもColorを適用

struct CircleView: View {
    var body: some View {
        Circle()
            .frame(width: 10, height: 10)
            .keyframeAnimator(
                initialValue: AnimationValues(
                    scale: 1,
+                   color: .black
                )
            ) { content, value in
                content
                    .scaleEffect(x: value.scale, y: value.scale)
            } keyframes: { _ in
                
                KeyframeTrack(\.scale) {
                    CubicKeyframe(4, duration: 4)
                    SpringKeyframe(10, duration: 4, spring: .bouncy)
                }
                
+               KeyframeTrack(\.color) {
+                   CubicKeyframe(.red, duration: 8)
+               }
            }
        
    }
}

ColorはAnimatableに準拠していない

すると、ColorAnimatableに準拠していない為、エラーが発生します。

conform to animatable

Animatableに準拠しているタイプを使用する

Animatableのドキュメントの中にConfirming Typesという項目があり、その中にColor.Resolvedというものが準拠しているタイプとして含まれていました。

Color.Resolved

こちらもiOS 17から追加された構造体で、Colorを表す為のRBGAのセットです。

Color.Resolved is a set of RGBA values that represent a color that can be shown

引用: Color.Resolved | Apple Developer Documentation

Color.ResolvedをColorの代わりに使用する

アニメーションの値をColor.Resolvedに変更

struct AnimationValues {
    var scale: CGFloat
-   var color: Color
+   var color: Color.Resolved
}

keyframeAnimatorにもColor.Resolvedを適用

struct CircleView: View {
    var body: some View {
        Circle()
            .frame(width: 10, height: 10)
            .keyframeAnimator(
                initialValue: AnimationValues(
                    scale: 1,
-                   color: .black
+                   color: Color.black.resolve(in: .init())
                )
            ) { content, value in
                content
+                   .foregroundStyle(value.color)
                    .scaleEffect(x: value.scale, y: value.scale)
            } keyframes: { _ in
                
                KeyframeTrack(\.scale) {
                    CubicKeyframe(4, duration: 4)
                    SpringKeyframe(10, duration: 4, spring: .bouncy)
                }
                
                KeyframeTrack(\.color) {
+                   CubicKeyframe(Color.red.resolve(in: .init()), duration: 6)
+                   CubicKeyframe(Color.blue.resolve(in: .init()), duration: 2)
                }
            }

    }
}

colorの方は、6秒間かけて赤色に変化し、その後2秒間かけて青色に変化するアニメーションを付与してみました。

demo 2

colorもアニメーションさせることが出来ました。

おわりに

KeyFramesのアニメーションが出来るようになり、私は非常に興奮しております。

littleossa

参考

https://developer.apple.com/documentation/swiftui/keyframes
https://developer.apple.com/documentation/swiftui/springkeyframe
https://developer.apple.com/documentation/swiftui/animatable
https://developer.apple.com/documentation/swiftui/color/resolved

Discussion