SwiftUI Transition の基本

Transition は、ビューが画面に現れたり消えたりするときのアニメーションを定義する。if 文や ForEach でビューの表示・非表示を切り替える際に、フェードやスライドといった効果を簡単に追加できる。

transition モディファイアの基本

struct ContentView: View {
    @State private var showDetail = false
    
    var body: some View {
        VStack {
            if showDetail {
                Text("詳細情報")
                    .padding()
                    .background(Color.blue)
                    .transition(.opacity)
            }
            
            Button("Toggle") {
                withAnimation {
                    showDetail.toggle()
                }
            }
        }
    }
}

.transition(.opacity) により、テキストがフェードイン・フェードアウトする。withAnimation で囲むことを忘れないこと。

組み込みの Transition

SwiftUI にはいくつかの Transition がプリセットとして用意されている。

.transition(.opacity)           // フェード
.transition(.scale)             // 中心から拡大縮小
.transition(.slide)             // 横からスライド
.transition(.move(edge: .top))  // 指定した辺からスライド
.transition(.push(from: .bottom)) // プッシュ(iOS 16+)
opacity透明度が 0 から 1 に変化
scaleスケールが 0 から 1 に変化
slideleading から trailing へスライド(RTL 対応)
move指定した edge からスライド
push指定方向からプッシュ(既存ビューを押し出す)

combined で複数の Transition を組み合わせる

.transition(.opacity.combined(with: .scale))

フェードとスケールが同時に適用され、より印象的な効果になる。3 つ以上も組み合わせ可能だ。

.transition(
    .opacity
    .combined(with: .scale)
    .combined(with: .move(edge: .bottom))
)

asymmetric で挿入と削除を別々に

挿入時と削除時で異なる Transition を使いたい場合は asymmetric を使う。

.transition(.asymmetric(
    insertion: .move(edge: .trailing).combined(with: .opacity),
    removal: .move(edge: .leading).combined(with: .opacity)
))

この例では、挿入時は右からスライドイン、削除時は左へスライドアウトする。カルーセルやページ遷移のような効果に使える。

scale と anchor

scale Transition には anchor パラメータでスケールの基準点を指定できる。

.transition(.scale(scale: 0.5, anchor: .topLeading))

デフォルトは .center だが、.topLeading や .bottomTrailing を指定すると、その角を基準に拡大縮小する。

Transition とアニメーションの組み合わせ

Transition 自体にアニメーションを指定することもできる。

.transition(
    .scale
    .animation(.spring(duration: 0.5, bounce: 0.3))
)

これにより、withAnimation で指定したアニメーションとは別の動きを Transition に与えられる。

適用される条件

Transition が適用されるのは、ビューが条件分岐によって追加・削除されるときだ。

Transition が適用される

if showDetail { DetailView().transition(.slide) } のように、ビュー自体の有無が変わる場合。

Transition が適用されない

.opacity(showDetail ? 1 : 0) のように、ビューは常に存在し、プロパティだけが変わる場合。これは通常のアニメーション。

ビューの出現・消失に対しては Transition を、ビューのプロパティ変更に対しては animation を使うという使い分けが基本になる。