はじめに
withAnimation
にパラメータが2つ増えました。
まず、1つ目はアニメーションの終了が検知できるようにcompletion
が追加されました。
2つ目はアニメーションの終了をどことするかを指定するcompletionCriteria
です。
解説していきます。
アニメーションの終了が検知できるようになった
import SwiftUI
struct ContentView: View {
@State private var degrees: Double = 0.0
@State private var status = ""
var body: some View {
VStack(spacing: 60) {
Text(status)
Rectangle()
.frame(width: 200, height: 200)
.rotationEffect(.degrees(degrees))
Button {
status = "アニメーション中です"
withAnimation(.default) {
degrees = (degrees == 360 ? 0 : 360)
} completion: {
status = "アニメーションが終了しました!"
}
} label: {
Text("アニメーション開始")
}
.buttonStyle(.borderedProminent)
}
}
}
意外と便利ですね。
疑問が生まれる
バウンドするようなアニメーションではアニメーションさせるための、力を加えるのを終了しても惰性で動き続けます。
そのようなアニメーションではどこがアニメーションの終わりなのでしょうか?
考えられるアニメーション終了地点は2箇所あります。
- アニメーションさせる力を加えることを終了した時
- アニメーションが完全に停止した時
これを指定するのがcompletionCriteria
です。
completionCriteria
を指定してみる
アニメーションさせる力を加えることを終了した時
import SwiftUI
struct ContentView: View {
@State private var degrees: Double = 0.0
@State private var status = ""
var body: some View {
VStack(spacing: 60) {
Text(status)
Rectangle()
.frame(width: 200, height: 200)
.rotationEffect(.degrees(degrees))
Button {
status = "アニメーション中です"
withAnimation(.bouncy(duration: 3.0, extraBounce: 0.3), completionCriteria: .logicallyComplete) {
degrees = (degrees == 360 ? 0 : 360)
} completion: {
status = "アニメーションが終了しました!"
}
} label: {
Text("アニメーション開始")
}
.buttonStyle(.borderedProminent)
}
}
}
アニメーションが完全に停止した時
import SwiftUI
struct ContentView: View {
@State private var degrees: Double = 0.0
@State private var status = ""
var body: some View {
VStack(spacing: 60) {
Text(status)
Rectangle()
.frame(width: 200, height: 200)
.rotationEffect(.degrees(degrees))
Button {
status = "アニメーション中です"
withAnimation(.bouncy(duration: 3.0, extraBounce: 0.3), completionCriteria: .removed) {
degrees = (degrees == 360 ? 0 : 360)
} completion: {
status = "アニメーションが終了しました!"
}
} label: {
Text("アニメーション開始")
}
.buttonStyle(.borderedProminent)
}
}
}
おわり
自分で実装するとめんどくさそうですよね
公式ドキュメント