はじめに
今回は@Environment
のアウトプットとして書きます。
今回作成するもの
ボタンを押すとピンクの画面が表示され、閉じるボタンを押すとピンクの画面が閉じるような簡単なものを例に作成してみます。
今回は@Environment
を使用する前に、以前にやった@Binding
を用いて画面の切り替えをまずは行なってみます。
@Binding
を用いて作成する
まずは初めの白い画面を作成します。
struct ContentView: View {
@State var isShow = false
var body: some View {
Button(action: {
isShow = true
}, label: {
Text("画面を表示")
.font(.largeTitle)
})
.fullScreenCover(isPresented: $isShow) {
SecondView(isPresented: $isShow)
}
}
}
ピンクの画面(SecondView
)が表示するかどうかを管理するisShow
プロパティを用意します。
Button
をタップするとSecondView
を表示させるのでButton action
でisShow = true
とします。
fullScreenCoverのisPresented
引数の真偽値によって画面が表示されるかどうか決まり、content
引数はクロージャでContent
を返すので、ここに表示させたいView(SecondView)
を書きます。
struct SecondView: View {
@Binding var isPresented: Bool
var body: some View {
NavigationView {
VStack {
Text(isPresented ? "表示されている" : "非表示になった")
.font(.largeTitle)
.foregroundColor(.green)
Button(action: {
isPresented = false
}, label: {
Text("閉じる")
.font(.largeTitle)
})
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.pink)
}
}
}
今回の例ではSecondView
からContentView
に閉じるボタンがタップされたらContentView
のisShow
をfalse
にしてSecondView
を閉じなければならないので、SecondView
のisPresented
とContentView
のisShow
を@Binding
によって結び、isPresented
が変更されたらその変更を参照させているisShow
に知らせます。
Button action
でisPresented = false
とします。
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
SecondView(isPresented: Binding.constant(false))
}
}
また、プレビューでもSecondView
を表示させたいのでContentView_Previews
にSecondView(isPresented: Binding.constant(false))
を追加します。
Binding.constant(false)
とすることでSecondView isPresented
にfalse
を初期値として入れることができます。
@Environment
を使って書き換える
ここから本題ですが、先ほどの@Binding
を使って作成したものを@Environment
を使って書き換えます。
iOS14とiOS15以降で変更された箇所があるので両方記載してみます。
iOS14の場合
struct SecondView: View {
@Environment(\.presentationMode) var presentation
var body: some View {
NavigationView {
VStack {
Text(presentation.wrappedValue.isPresented ? "表示されている" : "非表示になった")
.font(.largeTitle)
.foregroundColor(.green)
Button(action: {
presentation.wrappedValue.dismiss()
}, label: {
Text("閉じる")
.font(.largeTitle)
})
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.pink)
}
}
}
@Binding
の部分を@Environment(\.presentationMode) var presentation
に変更します。これは、@Environment
を用いてEnvironmentValuesの一つであるpresentationMode
にアクセスする変数presentaion
を定義しています。
この変数を使うことで画面の状態(presentation.wrappedValue.isPresented
)や画面を閉じる処理(presentation.wrappedValue.dismiss()
)を扱うことができます。
wrappedValue
でラップされている内部変数を使ってisPresented
やdismiss()
で処理することができます。
struct ContentView: View {
@State var isShow = false
var body: some View {
Button(action: {
isShow = true
}, label: {
Text("画面を表示")
.font(.largeTitle)
})
.fullScreenCover(isPresented: $isShow) {
SecondView()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
SecondView()
}
}
ContentView
とContentView_Previews
でそれぞれSecondView
をインスタンス化している部分はそれぞれ@Binding
から@Environment
に変更されたので初期値を入れる必要はなくなりました。
iOS15以降の場合
先ほどのpresentaionMode
を使用する方法は残念ながらiOS14から非推奨になってしまいました。こちらではiOS15からの方法を書いてみます。
struct SecondView: View {
// @Environment(\.presentationMode) var presentation
@Environment(\.isPresented) var isPresented
@Environment(\.dismiss) var dismiss
var body: some View {
NavigationView {
VStack {
Text(isPresented ? "表示されている" : "非表示になった")
.font(.largeTitle)
.foregroundColor(.green)
Button(action: {
dismiss()
}, label: {
Text("閉じる")
.font(.largeTitle)
})
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.pink)
}
}
}
ContentView
とContentView_Previews
に変更はありません。
SecondView
の@Environment
のEnvironmentValues
がisPresented
とdismiss
になっています。
@Environment(\.isPresented) var isPresented
@Environment(\.dismiss) var dismiss
さらに、presentation.wrappedValue.isPresented
はisPresented
になり、presentation.wrappedValue.dismiss()
はdismiss()
とシンプルになっています。
ちなみに、dismiss()
の部分はdismiss.callAsFunction()
としても同じようです。
iOS14までのpresentationMode
からもともと提供されていたisPresented
とdismiss
ですが、iOS15からはEnvironmentValues
として扱いやすくなりました。
こちらのドキュメントにisPresented
やdismiss
以外のEnvironmentValues
が載っているので一度見てみても面白いかもしれません。
おわりに
SwiftUI学習始めたばかりなので、間違ってる点がありましたらTwitterまたはコメントで"やさしく"教えてくださいませ。