見出し画像

【SwiftUI】フェードアニメーションで画面遷移を行う

概要


SwiftUIで画面遷移をする方法の1つとして「表示フラグを使用して遷移をコントロールする」というものがあります。

詳しくは、以前書いた記事を読んでいただければ幸いです。

この方法を使う場合は、画面遷移のアニメーションは自分で書く必要があります。
今回は画面遷移に使われるようなアニメーションの基礎を理解するためにフェードアニメーションによる画面遷移を実際に書いて試してみました。

環境

・Swift: 5.2.2
・Xcode: 11.4.1

完成イメージ

画像1

遷移元の画面

まずは遷移元の画面を作成します。

スクリーンショット 2020-05-16 12.01.27

struct FirstView: View {
   @State var isPresented = false
   var body: some View {
       ZStack {
           VStack {
               Button("Show FadeView") {
                   self.isPresented.toggle()
               }
           }
           // NOTE: Boolのフラグで表示非表示を分ける
           if isPresented {
               FadeView(isPresented: $isPresented)
           }
       }
   }
}

フェードアニメーションで表示する画面  FadeView をボタン押下で表示します。
表示制御は、@StateのBoolの値(isPresented)をボタン押下時に変更することで行っており、isPresentedがtrueなら FadeView を描画するように制御しています。
画面を閉じる制御をFadeView上で行うためにisPresentedをFadeViewに渡しています。
(詳細は後述するFadeViewの実装をみてください)

フェードアニメーションで表示する画面

次に実際にフェードアニメーションで遷移する画面を作ります。

スクリーンショット 2020-05-16 12.01.36

struct FadeView: View {
   @State var opacity: Double = 0
   @Binding var isPresented: Bool
   
   var body: some View {
       ZStack(alignment: .topLeading) {
           VStack {
               Text("SecondView")
           }
           .frame(maxWidth: .infinity, maxHeight: .infinity)
           Button(action: {
               withAnimation(.linear(duration: 0.3)) {
                  // NOTE: 画面非表示の再描画に対してアニメーションを適用する
                   self.isPresented = false
               }
           }) {
               Text("閉じる")
                   .foregroundColor(Color.white)
           }
       }
       .frame(maxWidth: .infinity, maxHeight: .infinity)
       .background(Color.blue)
       .opacity(self.opacity)
       .onAppear {
           withAnimation(.linear(duration: 0.3)) {
               // NOTE: opacityを変更する画面再描画に対してアニメーションを適用する
               self.opacity = 1.0
           }
       }
   }
}

この画面では、左上の 閉じるボタン を押下することで画面を閉じることができます。
これは、親画面から渡された isPresented のフラグをfalseに変更することで実現しています。

画面表示のフェードインアニメーション

.onAppear {
 withAnimation(.linear(duration: 0.3)) {
   self.opacity = 1.0
 }
}

画面表示のフェードインアニメーションは、画面(ZStack)の onAppear に記述しています。
アニメーションには、SwiftUIでアニメーションを実装するときに便利な関数である 「withAnimation」 を使っています。

withAnimation は引数のクロージャ内で発生した画面描画に対してアニメーションを付けてくれる関数です。

上記処理では画面の透明度(opacity)を 0.0 から 1.0 に変更する処理をonAppearで行っており、この処理による再描画にアニメーションをつけることでフェードインアニメーションを適用しています。

withAnimation には、アニメーションの種類を引数として渡すことができます。
渡せるアニメーションの種類には、各種イージングなど様々なものが用意されていますが、今回は linear アニメーションを使用しています。
アニメーションによって実行時間も指定できます。
(今回は0.3秒でアニメーションしています。)

画面非表示のフェードアウトアニメーション

Button(action: {
   withAnimation(.linear(duration: 0.3)) {
       self.isPresented = false
   }
}) {
   Text("閉じる")
       .foregroundColor(Color.white)
}

画面を閉じる時のフェードアウトアニメーションです。
呼び出し画面から渡された isPresented フラグをfalseにすることで親画面が再描画され、FadeViewは非表示になります。
この際に画面表示と同様に withAnimation 関数を使用することでフェードアウトのアニメーションを適用することができます。
アニメーションの種類については、画面表示と同様のため説明は割愛します。

まとめ

SwiftUIでは、それほど複雑なアニメーションでなければシンプルにアニメーションを記述することができます。
フラグで画面遷移を実装することはNavigationLinkなどと比べると手間はかかりますが、アニメーションをカスタマイズできるという面では使い勝手は自由なので面倒くさがらず使っていこうと思います。

この記事が気に入ったらサポートをしてみませんか?