5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【SwiftUIパターン】Environment Modifiers

Last updated at Posted at 2020-08-13

名前

Environment Modifiers1

コンテキスト

SwiftUIでは.environment<V>(_ keyPath: WritableKeyPath<EnvironmentValues, V>, _ value: V) -> some View2という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パターンを利用して、環境値注入のシンタックスシュガーを提供します。

例えば、標準のコンポーネントを見ても、Textfont(Font?) -> TextというAPIは.environmentのシンタックスシュガー4です。

environment
Text("abc")
    .environment(\.font, .body)
糖衣構文.swift
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

名前は勝手に付けており「もっとこの名前の方が端的に概念を表せているのはないでしょうか?」や「このようなパターンとして記述した方が良いのではないでしょうか?」などの議論は歓迎していますので、どうぞよろしくお願いします。

  1. 命名は、以下の記事から借りてきました。https://www.hackingwithswift.com/books/ios-swiftui/environment-modifiers

  2. https://developer.apple.com/documentation/swiftui/link/environment(_:_:)?changes=latest_beta

  3. https://developer.apple.com/documentation/swiftui/environmentvalues

  4. 内部実装を見たわけでは無いので、推測です

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?