LoginSignup
0
1

【SwiftUI】PhaseAnimatorを使って繰り返しアニメーションを作成する(iOS17)

Posted at

はじめに

昨日、繰り返しのアニメーションはTimelineViewが相性良さそうっていう記事を書いたんですが、もっと繰り返しアニメーションに適しているものがありました。

それはPhaseAnimatorです。
iOS17から使用できるようになったようです。

PhaseAnimatorを使ってアニメーションを作ってみました。

サンプルアプリ

Simulator Screen Recording - iPhone 15 - 2023-12-07 at 21.20.16.gif

実装

円の周りに放射状の線を設置するためのView

import SwiftUI

struct RadialLineShape: Shape {
    func path(in rect: CGRect) -> Path {
        let radius = rect.width / 2
        let degreeSeparation : Double = 360.0 / Double(20)
        var path = Path()
        for index in 0..<Int(360.0/degreeSeparation) {
            let degrees = Double(index) * degreeSeparation
            let center = CGPoint(x: rect.midX, y: rect.midY)
            let innerX = center.x + (radius - rect.size.width * 0.3 / 2) * CGFloat(cos(degrees / 360 * Double.pi * 2))
            let innerY = center.y + (radius - rect.size.width * 0.3 / 2) * CGFloat(sin(degrees / 360 * Double.pi * 2))
            let outerX = center.x + radius * CGFloat(cos(degrees / 360 * Double.pi * 2))
            let outerY = center.y + radius * CGFloat(sin(degrees / 360 * Double.pi * 2))
            path.move(to: CGPoint(x: innerX, y: innerY))
            path.addLine(to: CGPoint(x: outerX, y: outerY))
        }
        return path
    }
}
import SwiftUI

enum BoltPhase: CaseIterable {
    case state1
    case state2
}

extension BoltPhase {
    var rotationEffect: Angle {
        return switch self {
        case .state1: .degrees(0)
        case .state2: .degrees(-30)
        }
    }
    
    var backgroundOpacity: CGFloat {
        return switch self {
        case .state1: 0.8
        case .state2: 1.0
        }
    }
    
    var radialLineShapeOpacity: CGFloat {
        return switch self {
        case .state1: 1.0
        case .state2: 0.0
        }
    }
}

struct ContentView: View {
    var body: some View {
        PhaseAnimator(BoltPhase.allCases) { phase in
            Image(systemName: "bolt.fill")
                .resizable()
                .scaledToFit()
                .frame(width: 150, height: 150)
                .foregroundStyle(.yellow.gradient.shadow(.drop(radius: 3)))
                .rotationEffect(phase.rotationEffect)
                .padding(15)
                .background(.orange.gradient.shadow(.drop(radius: 3)).opacity(phase.backgroundOpacity), in: .circle)
                .overlay {
                    RadialLineShape()
                        .stroke(.yellow.gradient.opacity(phase.radialLineShapeOpacity), lineWidth: 3.0)
                        .frame(width: 350, height: 350)
                }
        }
    }
}

おわり

iOS17でアニメーション周りがめっちゃ強化された感じありますね

公式ドキュメント

参考記事

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1