SwiftUIではEnvironmentValuesが多数用意されており、Viewから@Environmentで参照する事が出来ます。
システムで設定された値を読み取ったり、設定した値が子Viewで読み取る事ができ非常に便利です。
今回はこのEnvironmentValueに独自のものを追加する方法を紹介します。
Read Onlyになる基本形と、変更可能な形式の2種を紹介します。
EnvironmentValueの追加(Read Only)
まずはRead Onlyの基本形です。
struct ReadOnlyKey:EnvironmentKey {
static let defaultValue = "ReadOnlyValue"
}
extension EnvironmentValues {
var readOnlyValue: String {
get{ self[ReadOnlyKey.self] }
set{ self[ReadOnlyKey.self] = newValue }
}
}
Keyの構造体を定義しEnvironmentValuesにプロパティとして追加します。
追加するコード自体はこれだけです。
実際に使って確認してみましょう。
struct ContentView: View {
@Environment(\.readOnlyValue) var readOnlyValue
var body: some View {
Text(readOnlyValue)
.padding()
}
}
既存のEnvironmentValueと同じですね。
@Environmentで指定するのは、Key構造体の名前ではなくEnvironmentValuesに追加したプロパティ名である事に注意してください。
親Viewから値を指定して渡す時は以下の様になります。
@main
struct EnvironmentValueTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.readOnlyValue, "TestValue")
}
}
}
これも既存のものと同じですね。
非常に簡単に実装できますので、子Viewへ値を渡したい時に非常に便利なので是非活用してみてください。
値が変更できるEnvironmentValue
EnvironmentKeyにBindingを使います。
正確に言うとEnvironmentValueの値は変わっていませんが、
おおよそEnvironmentValueの値を変えると言われてイメージするものだと思います。
struct BindingKey:EnvironmentKey {
static let defaultValue:Binding<String> = .constant("BindingValue")
}
extension EnvironmentValues {
var bindingValue:Binding<String> {
get{ self[BindingKey.self] }
set{ self[BindingKey.self] = newValue }
}
}
Bindingを使うので中身の値を変更する事が出来ます。
また、Bindingなので変更に応じたViewの再描画が起こります。
使う時にはいくつか注意が必要です。
まず1つ目は親Viewで@Stateでマークした変数をenvironmentで渡す必要があります。
@main
struct EnvironmentValueTestApp: App {
@State var stateValue = "StateValue"
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.bindingValue, $stateValue)
}
}
}
もう1つは、あくまで@BindingでなくBinding<>だと言うことです。
値を扱うには変数名.wrappedValueが必要です。
EditModeのようなイメージですね。
struct ContentView: View {
@Environment(\.bindingValue) var bindingValue
var body: some View {
VStack {
Text(bindingValue.wrappedValue)
.padding()
Button("Change"){
bindingValue.wrappedValue = "Test"
}
}
}
}
@Bindingで使いたい場合は@Environmentの後に書きます。
struct ContentView: View {
@Environment(\.bindingValue) @Binding var bindingValue
var body: some View {
VStack {
Text(bindingValue)
.padding()
Button("Change"){
bindingValue = "Test"
}
}
}
}
これで中身の値が変更できるEnvironmentValueができました。
SwiftUI標準で用意されているEnvironmentValueに近い扱いが出来るので、
非常に便利でありコードの統一感もでて読みやすくなると思います。
コメント