Viewオブジェクトの表示・非表示切り替えに伴うアニメーションをトランジション(transition)と呼びます。
SwiftUIでは、トランジション用に通常のアニメーション処理とは別の仕組みが用意されています。
環境
この記事の情報は次のバージョンで動作確認しています。
【Swift】5.2.4
【iOS】13.5
【macOS】Catalina バージョン 10.15.4
基本的な使い方
トランジションを使うには、対象のViewにtransitionモデファイアを適用します。
1 2 3 |
transition(AnyTransition) |
引数のAnyTransition構造体で、トランジション専用のアニメーションを定義します。
定義可能なアニメーションタイプは以下の通りです。
.slide
左からスライドして出現し、右へスライドして消えていきます。
.opacity
透明な状態からだんだん出現し、消える時もだんだんと透明になっていきます。
.scale
拡大しながら表示、縮小しながら消えていきます。
.scale(scale: CGFloat, anchor: UnitPoint = .center)
拡大しながら表示、縮小しながら消える効果を細かく指定できます。
第1引数(scale)には、拡大・縮小の倍率、第2引数(anchor)には、変化の起点となる位置をUnitPoint構造体で指定します。
anchorが未指定時のデフォルト値は.centerです。
.move(edge: Edge)
引数(edge)で指定された方向(.top、.leading、.bottom、.trailingのいずれか)から表示、同方向へ消えていきます。
.offset(CGSize)
CGSize構造体で指定されたオフセット位置から移動しながら表示、同じ位置へ移動しながら非表示になります。
.offset(x: CGFloat = 0, y: CGFloat = 0)
上と同様の効果。オフセット位置を、数値で直接指定します。
.identity
トランジション効果を行いません。
動作条件
動作条件として、Viewの表示・非表示切り替えを行うプロパティに対して明示的にアニメーションが適用されている必要があります。
「プロパティに対して」の部分がポイントです。Viewに対してanimationが適用されているだけでは、トランジションが機能しないケースがあります。
プロパティに対するアニメーション指定とViewに対するアニメーション指定についてはこちらの記事【SwiftUI】アニメーションの基本で解説しています。
なお、animationで指定した効果と、transitionで指定した効果は合成されます。
使用例
「トランジション」ボタンをタップすると、青い円が右へスライドしながら消えていきます。
再びタップすると左から現れます。
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("トランジション") { withAnimation() { // 明示的なアニメーション指定 self.flag.toggle() } } if flag { Circle() .fill(Color.blue) .frame(width: 100, height: 100) .transition(.slide) // トランジションの適用 } } } } |
transitionの合成(combined)
AnyTransition構造体のインスタンスは、combindモデファイアでトランジション効果を合成できます。
複数重ねての適用もできます。
1 2 3 |
combined(width: AnyTransition) |
引数(width)で重ねて合成するトランジション効果を定義します。
combined()メソッドはAnyTransition構造体のインスタンスに対して呼び出されるので、AnyTransitionの型を明示的に指定する必要があります。
使用例
次のコードは、opacityとoffsetを合成した例です。
透明度を変えながら右下に消えていき、再び右下から現れます。
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("トランジション") { withAnimation() { self.flag.toggle() } } if flag { Circle() .fill(Color.blue) .frame(width: 100, height: 100) .transition(AnyTransition.opacity.combined(with: .offset(x: 100, y: 50))) // トランジションの適用 } } } } |
非対称トランジション(asymmetric)
asymmetricメソッドを使うと、Viewの表示と非表示で異なるトランジション効果を適用できます。
1 2 3 |
asymmetric(insertion: AnyTransition, removal: AnyTransition) |
第1引数(insertion)で、表示時のトランジション効果を指定。
第2引数(removal)で、非表示時のトランジションを指定します。
使用例
次のコードは、拡大しながら表示し、右へスライドしながら消えていくサンプルです。
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("トランジション") { withAnimation() { self.flag.toggle() } } if flag { Circle() .fill(Color.blue) .frame(width: 100, height: 100) /// 非対称トランジションを指定 .transition(.asymmetric(insertion: .scale, removal: .slide)) } } } } |