はじめに
今回はWWDC2023の以下動画で見たphaseAnimatorについて実際に触ってキャッチアップしてみました。
普段SwiftUIでAnimationを付与するときは、withAnimationでanimatableなmodifierの値を変更するなどして行うのですが、そういった方法とは少しやり方が違いそうです。
早速みていきましょう。
phaseAnimatorとは
まずは公式のドキュメントを見てみます。
アニメーション内の個別のステップを定義する、提供されたフェーズのコレクションを自動的に循環させることでコンテンツをアニメーション化するコンテナー。
概要
アプリで段階的なアニメーションを作成するには、フェーズ アニメーター ビュー モディファイアのいずれかを使用します。phaseAnimator(_:content:animation:)nonisolated func phaseAnimator<Phase>( _ phases: some Sequence, @ViewBuilder content: @escaping (PlaceholderContentView<Self>, Phase) -> some View, animation: @escaping (Phase) -> Animation? = { _ in .default } ) -> some View where Phase : Equatable
phaseAnimator
モディファイアのphases
に設定した配列を自動で循環してアニメーションさせるようです。
と自分で書いていてもイマイチピンとこないので、手を動かします。
無限ループのAnimation
struct MultiStepAnimationView: View {
var body: some View {
Text("Hello, World!")
.font(.system(size: 24, weight: .bold))
.phaseAnimator([1, 2, 3]) { view, phase in
view
.opacity(phase == 2 ? 1 : 0)
.scaleEffect(phase * 0.5)
}
}
}
phaseAnimator
モディファイアのcontent
引数にて、Animationしたい内容を実装することで、phases
で指定した配列を無限に循環してAnimationが無限ループで再生されるようになりました。
また、以下のように各phase毎にAnimationも指定できました。
そこまで細かくAnimationを指定したいケースは,今のところ遭遇したことがないですが、やろうと思えば相当細かく設定できそうです。
struct MultiStepAnimationView: View {
var body: some View {
Text("Hello, World!")
.font(.system(size: 24, weight: .bold))
.phaseAnimator([1, 2, 3], content: { view, phase in
view
.opacity(phase == 2 ? 1 : 0)
.scaleEffect(phase * 0.5)
}, animation: { phase in
phase == 2 ? .spring : .linear(duration: 1)
})
}
}
トリガー付きのAnimation
struct TriggeredMultiStepAnimationView: View {
@State var trigger = 0
var body: some View {
VStack {
Spacer()
Rectangle()
.frame(width: 100, height: 100)
.phaseAnimator([1,2,3], trigger: trigger) { view, phase in
view
.opacity(phase == 2 ? 0 : 1)
.rotationEffect(.degrees(phase == 2 ? 360 : 0))
.foregroundStyle(phase == 1 ? .red : .blue)
}
Spacer()
Button {
trigger += 1
} label: {
Text("START")
}
}
}
}
trigger
付きのphaseAnimator
モディファイアを使用した場合、前の例とは違い無限ループのAnimationではなくなります。
trigger
に設定したEqutableの値に変更が加えられると、設定したAnimationが発火します。
また、Animationが発火していない状態ではphases
に指定した最初の値で設定したモディファイアの状態が適用されます。
上記の例ですと、通常の状態はphases
が1の状態でopacity
、rotationEffect
、foregroundStyle
が適用されています。
おわり
思ったより簡単にオリジナルのアニメーションが作れて楽しかったです。
試しにオリジナルのロードアニメーション作ってみました。
こういうAnimationは以前はTimerとか使ってやっていましたが、phaseAnimatorを使うと簡単に実装できます。
実装は以下リポジトリに上げました。