Inlining @Environment access in SwiftUI

The @Environment modifier in SwiftUI is a core data-flow primitive, that allows one to access environment values set by the parent.

Example usage:

struct Foo: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Group {
            if colorScheme == .light {
                Text("Light")
            } else {
                Text("Dark")
            }
        }
    }
}

This is all well and good - but note that @Environment is implemented as a property wrapper and cannot be used without a housing View structure.

In prototyping code heavily reliant on @Environment, this can feel cumbersome and boilerplate-y. Hence, I wrote a simple generic wrapper to solve this problem:

public struct EnvironmentValueAccessView<EnvironmentValue, Content: View>: View {
    private let keyPath: KeyPath<EnvironmentValues, EnvironmentValue>
    private let content: (EnvironmentValue) -> Content

    @Environment var environmentValue: EnvironmentValue

    public init(
        _ keyPath: KeyPath<EnvironmentValues, EnvironmentValue>,
        @ViewBuilder content: @escaping (EnvironmentValue) -> Content
    ) {
        self.keyPath = keyPath
        self.content = content

        self._environmentValue = .init(keyPath)
    }

    public var body: some View {
        content(environmentValue)
    }
}

With EnvironmentValueAccessView now, we can express our example code as a simple inline expression:

        EnvironmentValueAccessView(\.colorScheme) { colorScheme in
            if colorScheme == .light {
                Text("Light")
            } else {
                Text("Dark")
            }
        }
 
12
Kudos
 
12
Kudos

Now read this

Reimplementing SwiftUI’s deprecated relative view sizing functions.

With Xcode 11 beta 4, Apple deprecated SwiftUI’s View.relativeSize function (as well as View.relativeWidth and View.relativeHeight). The relativeWidth(_:), relativeHeight(_:), and relativeSize(width:height:) modifiers are deprecated. Use... Continue →