この記事は何?
SwiftUIアプリのシートやポップオーバー表示を取り消す方法について、Appleの開発者向けドキュメントを独自に解説する。
Swiftを基礎から学ぶには
自著、工学社より発売中の「まるごと分かるSwiftプログラミング」をお勧めします。変数、関数、フロー制御構文、データ構造はもちろん、構造体からクロージャ、エクステンション、プロトコル、クロージャまでを基礎からわかりやすく解説しています。
dismissプロパティ
Dismiss環境値を使用して、特定の環境に対してこの構造体のインスタンスを取得する。
次に、インスタンスを呼び出すと、表示の取り消しを実行する。
インスタンスを呼び出すときにSwiftが呼び出すcallAsFunction()メソッドを定義するため、インスタンスを直接呼び出す。
このアクションを使用して、次のことができる。
- シートやポップオーバーなどのモーダル表示を取り消す
-
NavigationStackから現在のビューをポップする -
WindowGroupまたはWindowで作成したウィンドウを閉じる
アクションの具体的な動作は、どこから呼び出すかによって異なる。
たとえば、シートとして機能するビュー内でDismissActionを呼び出すボタンを作成できる。
// モーダル表示されるシート
private struct SheetContents: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
Button("Done") {
dismiss()
}
}
}
SheetContentsビューを表示すると、シートのボタンをタップしてシートを閉じることができる。
// 通常の画面
private struct DetailView: View {
// 「シートが表示されているかどうか」を追跡する状態プロパティ
@State private var isSheetPresented = false
var body: some View {
// ボタンをタップすると、シートがモーダル表示される
Button("Show Sheet") {
isSheetPresented = true
}
.sheet(isPresented: $isSheetPresented) {
SheetContents()
}
}
}
注意すべき点
アクションが適切な環境で定義されているかを確認する。
たとえば、上例のDetailViewビューでdismissプロパティを作成することは適切ではない。
そのようにして、dismiss()アクションを.sheet(item:onDismiss:content:)修飾子のコンテンツクロージャから呼び出しても、シートを正しく却下できない。
private struct DetailView: View {
@State private var isSheetPresented = false
@Environment(\.dismiss) private var dismiss // Applies to DetailView.
var body: some View {
Button("Show Sheet") {
isSheetPresented = true
}
.sheet(isPresented: $isSheetPresented) {
// .sheetモディファイア内でdismissアクションを呼び出さないこと
Button("Done") {
dismiss() // Fails to dismiss the sheet.
}
}
}
}
アクションは「それを宣言した環境」に適用される。
つまり、先の方法では、アクションが「sheetContentsの環境」ではなく「DetailViewビューの環境」に適用されてしまったので、シート表示が取り消されない。
実際に、このDetailViewビューがルートビューだった場合、macOSとiPadOSのdismiss()アクションはウィンドウを閉じる。
dismiss()アクションは「表示中でないビュー」に影響しない。
SwiftUIが「ビューを表示しているかどうか」を照会したい場合は、isPresented環境値を利用する。
isPresentedプロパティ
「環境に関連付けられたビュー」が表示中かどうか、を示す真偽値。
var isPresented: Bool { get }
この環境値を読み取るには、@Environmentプロパティラッパーを使用してプロパティを作成する。
@Environment(\.isPresented) private var isPresented
SwiftUIが「そのビューをいつ表示するか」を知りたい場合は、他の環境値を利用する。
たとえば、.onChange(of:perform:)修飾子を使用して、SwiftUIがビューを表示したときにアクションを実行する。
.onChange(of: isPresented) { isPresented in
if isPresented {
// Do something when first presented.
}
}
この.onChange(of:perform:)は、すでにナビゲーション階層にあるビューに戻るときなど、SwiftUIが特定のプレゼンテーションに対して複数回呼び出せる.onAppear(perform:)とは動作が異なる。
表示中のビューを取り消すには、dismissアクションを使用すること。