Viewオブジェクトの表示・非表示の切り替え時のアニメーションを定義するtransitionモディファイアは、animationとセットで使用する必要があります。
しかしながら、animationの指定方法によってtransitionが正しく機能しないケースがあるようです。
本記事では、transitionが機能しないケースを紹介します。
環境
この記事の情報は次のバージョンで動作確認しています。
【Swift】5.2.4
【iOS】13.5
【macOS】Catalina バージョン 10.15.4
ケース1:Viewに暗黙的なanimationを指定
Viewに対して暗黙的なアニメーションを指定したケースでは、一部のtransition効果が機能しません。
次のコードを実行して、「トランジション」ボタンをクリックすると、青い円がアニメーション効果を伴って表示・非表示が切り替わります。
しかし、transitionのオプションを.scaleまたは.opacityに変更すると、アニメーションが機能しません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
struct ContentView: View { @State private var flag = true var body: some View { VStack { Button("トランジション") { self.flag.toggle() } if flag { Circle() .fill(Color.blue) .frame(width: 100, height: 100) .animation(.default) // 暗黙的なアニメーションの指定 .transition(.slide) // トランジションの適用 } Spacer() } } } |
一部のサイトや書籍では「Appleはtransitionを明示的なanimationと一緒にしか使用できないように変更した」との情報もあるので、このケースでは機能しない方が正しい仕様なのかもしれません。
ケース2:AnyTransitionインスタンスにanimation適用
Appleの公式リファレンスマニュアルを見ると、AnyTransitionのインスタンスに、直接animationモディファイアを使用できると書いてあります。
次のコードを実行すると確かにそれは機能するのですが、transitionのオプションを.slideに変更すると機能しなくなります。
このケースでは、先程のケースとは逆で、.scaleまたは.opacity以外のオプションがなぜか機能しなくなるようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct ContentView: View { @State private var flag = true var body: some View { VStack { Button("トランジション") { self.flag.toggle() } if flag { Circle() .fill(Color.blue) .frame(width: 100, height: 100) .transition(AnyTransition.scale.animation(.default)) // トランジションの適用 } Spacer() } } } |
回避策
transitionを使用する場合は、次のコードように明示的なアニメーション指定をすると良いです。
プロパティに対する明示的なアニメーション指定の場合は、確認した限りすべてのtransitionオプションが正常に機能します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
struct ContentView: View { @State private var flag = true var body: some View { VStack { Button("トランジション") { withAnimation() { // 明示的なアニメーション指定 self.flag.toggle() } } if flag { Circle() .fill(Color.blue) .frame(width: 100, height: 100) .transition(.scale) // トランジションの適用 } Spacer() } } } |