SwiftUI withAnimation の基本
SwiftUI でアニメーションを実装する最も基本的な方法が withAnimation 関数だ。状態の変更をこの関数で囲むことで、その変更に伴う UI の更新がアニメーション付きで実行される。
基本的な使い方
withAnimation は状態変更を引数のクロージャ内で行う。
struct ContentView: View {
@State private var isExpanded = false
var body: some View {
VStack {
Rectangle()
.fill(.blue)
.frame(width: isExpanded ? 200 : 100,
height: isExpanded ? 200 : 100)
Button("Toggle") {
withAnimation {
isExpanded.toggle()
}
}
}
}
}ボタンをタップすると、四角形のサイズがスムーズに変化する。withAnimation を外すと、サイズは瞬時に切り替わってしまう。
アニメーションの指定
withAnimation の引数にアニメーションの種類を渡せる。
withAnimation(.easeInOut) {
isExpanded.toggle()
}
withAnimation(.spring()) {
isExpanded.toggle()
}
withAnimation(.linear(duration: 0.5)) {
isExpanded.toggle()
}引数を省略した場合は .default(.easeInOut ベース、約 0.35 秒)が適用される。
複数の状態を同時に変更
クロージャ内で複数の状態を変更すると、すべてが同じアニメーションで動く。
struct MultipleStateView: View {
@State private var offset: CGFloat = 0
@State private var opacity: Double = 1.0
@State private var scale: CGFloat = 1.0
var body: some View {
Circle()
.fill(.orange)
.frame(width: 100, height: 100)
.offset(y: offset)
.opacity(opacity)
.scaleEffect(scale)
.onTapGesture {
withAnimation(.easeInOut(duration: 0.6)) {
offset = offset == 0 ? -100 : 0
opacity = opacity == 1.0 ? 0.3 : 1.0
scale = scale == 1.0 ? 1.5 : 1.0
}
}
}
}タップするたびに、位置・透明度・スケールが同時にアニメーションする。
withAnimation と暗黙的アニメーションの違い
SwiftUI には .animation() モディファイアを使う「暗黙的アニメーション」もある。
withAnimation(明示的)
状態変更のタイミングを明示的に制御。どの変更をアニメーションさせるか選べる。
animation モディファイア(暗黙的)
特定のビューに対して、値が変わるたびに自動でアニメーション。制御が難しい場面も。
意図しないアニメーションを避けるため、withAnimation を使う明示的な方法が推奨される場面が多い。
completionHandler(iOS 17 以降)
iOS 17 からは、アニメーション完了時のコールバックを受け取れるようになった。
withAnimation(.easeInOut(duration: 0.5)) {
isExpanded.toggle()
} completion: {
print("アニメーション完了")
}連続したアニメーションや、アニメーション後の処理を実装する際に便利な機能だ。