【SwiftUI】iOS 15から使えるdismissアクションを使って画面を破棄する

2022.04.30

SwiftUIで画面遷移する際は、やや複雑な印象だったのですが、iOS 15から使えるdismissアクションを使用することで楽に画面の破棄を行えるようになりました。

環境

  • Xcode 13.3

dismiss

現在のプレゼンテーションを破棄するアクションです。

var dismiss: DismissAction { get }

使用する際は、@Environmentを付けて使用します。 この環境値を使用して、現在の環境のDismissActionインスタンスを取得することが出来ます。

@Environment(\.dismiss) private var dismiss

実際に画面を破棄する時は、dismiss()でインスタンスを呼び出して実行します。こちらはプロパティですが、callAsFunction()メソッドを定義しているため、 関数を呼び出すかのようにインスタンスを呼び出すことが出来ます。

dismiss()

使用例

遷移元

遷移先のViewを表示する為のプロパティisNextPresentedを準備して、ボタンを押すことでそのフラグを切り替えてフルスクリーンカバーで遷移先のViewを表示します。

import SwiftUI

struct ContentView: View {

    @State private var isNextPresented = false

    var body: some View {

        Button {
            isNextPresented.toggle()
        } label: {
            Text("NextViewに遷移")
        }
        .fullScreenCover(isPresented: $isNextPresented) {
            NextView()
        }
    }
}

遷移先

環境変数dismissを用意して、ボタンを押すとDismissアクションが実行されます。

import SwiftUI

struct NextView: View {

    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack(spacing: 32) {
            Text("Hello, Next!")

            Button {
                dismiss()
            } label: {
                Image(systemName: "x.circle")
                    .resizable()
                    .frame(width: 50, height: 50)
            }
        }
    }
}

デモ

dismiss()するだけで画面破棄できるのでより直感的になりました。

dismiss-demo

今回はフルスクリーンカバーでの遷移で試していますが、NavigationViewでの遷移でも同様に行えます。

if分岐で表示を切り替える時は使用できない

モーダルやNavigation遷移の際にはdismissを使用出来ましたが、下記のようにif分岐で表示を切り替える場合には、表示後のNextViewでdismiss()を実行しても画面が破棄されません。

struct ContentView: View {

    @State private var isNextPresented = false

    var body: some View {

        if isNextPresented {
            NextView()
        } else {
            Button {
                isNextPresented.toggle()
            } label: {
                Text("NextViewに遷移")
            }
        }
    }
}

そもそもif分岐によるViewの切り替えなので、見栄え上は画面が切り替わっていても実際は遷移はしていない為です。

Viewの表示状態を取得する

dismissは現在表示されていないViewには影響を与えないので、これまでは特にViewの表示状態については特に気にしていませんでした。

しかし、Viewの表示状態に応じて何らかの処理を行いたい場合もあると思います。その場合はisPresentedを使用して現在Viewが表示されているかどうかを取得することが出来ます。

@Environment(\.isPresented) private var isPresented

使用例

import SwiftUI

struct PresentView: View {

    @Environment(\.isPresented) private var isPresented

    var body: some View {

        if isPresented {
            Text("表示中")
        }
    }
}

おわりに

iOS 15まではPresentationModeを使用するケースがあったかと思いますが、現在は非推奨となっており、利用可能もiOS 13.0–15.4となっております。 このpresentationModeが今回dismissに切り替わったことでより直感的になったと私は感じました。

これからもSwiftUIの成長に期待していきたいですね。

参考