名前
Environment Modifiers1
コンテキスト
SwiftUIでは.environment<V>(_ keyPath: WritableKeyPath<EnvironmentValues, V>, _ value: V) -> some View
2というAPIがView Modifiersとして用意されており、これはシステム・自作を問わずEnvironmentValue3を注入するための便利なAPIです。
例えば、あるコンテナビューの中身を全て利用不可にしたい場合は、以下のように記述すればコンテナ以下のヒエラルキー全てに環境値を注入し、利用不可と出来ます。
Container {
ViewA()
ViewB()
}
.environment(\.isEnabled, false)
問題
環境値を多く利用するViewにおいて、このAPIだけだと以下のように同じ記述が何度も続き、直感的ではなくなってしまう問題があります。
Text("abc")
.environment(KeyPathA, value1)
.environment(KeyPathB, value2)
.environment(KeyPathC, value3)
.environment(KeyPathD, value4)
.environment(KeyPathE, value5)
そこで、頻出のものにはシンタックスシュガーを与えたいです。
解決法
Environment Modifiers
パターンを利用して、環境値注入のシンタックスシュガーを提供します。
例えば、標準のコンポーネントを見ても、Textのfont(Font?) -> Text
というAPIは.environment
のシンタックスシュガー4です。
Text("abc")
.environment(\.font, .body)
Text("abc")
.font(.body)
Environment Modifiers実装例
Viewのextensionにメソッドを足すだけの簡単な実装方法です。この時、some View
を返却値とします。
extension View {
func accessibilityEnabled(_ enabled: Bool) -> some View {
self.environment(\.accessibilityEnabled, enabled)
}
}
Environment Modifiers + 自作キー実装例
EnvironmentKeyから自作をする場合には以下のように実装します。この例では、SwiftUIの現状のAPIに不足しているfirstResponderについての環境値を注入することとしています。
struct FirstResponderKey : EnvironmentKey {
static var defaultValue: Bool = false
}
extension EnvironmentValues {
var firstResponder : Bool {
get {
return self[FirstResponderKey.self]
}
set {
self[FirstResponderKey.self] = newValue
}
}
}
extension View {
func firstResponder(_ value: Bool) -> some View {
self.environment(\.firstResponder, value)
}
}
// 利用箇所でのサンプル
struct YourClientView : View {
@Environment(\.firstResponder)
private var firstResponder: Bool
var body: some View { ... }
}
関係するパターン
今のところ思いついて無いです。
Contribution
名前は勝手に付けており「もっとこの名前の方が端的に概念を表せているのはないでしょうか?」や「このようなパターンとして記述した方が良いのではないでしょうか?」などの議論は歓迎していますので、どうぞよろしくお願いします。