LoginSignup
2
2

【SwiftUI】iOS17でwithAnimationが強化された

Posted at

はじめに

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)
        }
    }
}

Simulator Screen Recording - iPhone 15 - 2024-01-21 at 21.03.47.gif

意外と便利ですね。

疑問が生まれる

バウンドするようなアニメーションではアニメーションさせるための、力を加えるのを終了しても惰性で動き続けます。
そのようなアニメーションではどこがアニメーションの終わりなのでしょうか?
考えられるアニメーション終了地点は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)
        }
    }
}

Simulator Screen Recording - iPhone 15 - 2024-01-21 at 21.43.15.gif

アニメーションが完全に停止した時

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)
        }
    }
}

Simulator Screen Recording - iPhone 15 - 2024-01-21 at 21.44.48.gif

おわり

自分で実装するとめんどくさそうですよね

公式ドキュメント

2
2
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
2
2