TLDR
A set of properties that easily exposes app-wide configuration to our views. A good example is
\.colorScheme
that tell us if the device is currently in light or dark mode.
Hey folks! If you’re here, I’m going to guess that you’re an iOS developer or enthusiast, and you’re working with SwiftUI. Today, we’re going to learn how to define and use our own custom environment values.
What’s the Deal with Environment Values?
It’s essentially a singleton that exposes app-wide configuration to our views in a friendly way.
They are set of predefined properties, that allows us to access current aspects of the app’s behavior and appearance. For example the device’s current color scheme (dark or light), the device’s current locale, the device’s current calendar, and size class (basically screen sizes).
SwiftUI provides a bunch of these out of the box. Properties like \.colorScheme
, \.locale
, \.horizontalSizeClass
, \.calendar
, \dynamicTypeSize
and \.managedObjectContext
are all familiar environment values.
But what if we want to add our own properties to this mix? Well, you’re in luck! SwiftUI lets us define and use custom environment values. And believe me, it’s as cool as it sounds. Here’s how it’s done.
Defining Custom Environment Values
Let’s say we’re building a hot new social media app, “ChatterBox”. We want to have a feature that lets users switch between light and dark themes, but we also want to include a “neon” theme because, why not, it’s 2023! SwiftUI’s built-in \.colorScheme
environment value won’t cut it. So, let’s create our custom environment value.
First, we need to extend the EnvironmentValues
struct with a computed property to include our new theme value:
1
2
3
4
5
6
7
8
9
10
enum Theme {
case light, dark, neon
}
extension EnvironmentValues {
var theme: Theme {
get { self[ThemeKey.self] }
set { self[ThemeKey.self] = newValue }
}
}
In this snippet, Theme
would be an enumeration of the different themes (light, dark, neon). ThemeKey
is a key that we’ll define next.
We need to define a ThemeKey
that conforms to the EnvironmentKey
protocol as follows:
1
2
3
struct ThemeKey: EnvironmentKey {
static let defaultValue: Theme = .light
}
With this setup, defaultValue
is what’s used when no other value has been provided. Now let’s inject it into our views.
Injecting and Using Custom Environment Values
Now that we have our custom theme
environment value, how do we use it? Well, it’s as easy as pie 🥧.
We can inject the current theme into our parent view like this:
1
2
3
4
NavigationStack {
// Our awesome UI here
}
.environment(\.theme, .neon)
And voila! We’ve just injected the 'neon'
theme into the environment. Any view inside the NavigationStack can now access it.
To read from the newly inject value in our environment, we’d do something like this:
1
2
3
4
5
6
@Environment(\.theme) var theme
var body: some View {
Text("Welcome to ChatterBox!")
.foregroundColor(theme == .neon ? .purple : .primary)
}
And just like that the text color will now respond dynamically to the current theme, be it light, dark or neon.
Conclusion
As we just explored using custom environment values in SwiftUI is powerful. They make our UIs super flexible and responsive to changes in globally-defined values. Plus, they’re a blast to work with once you get the hang of it.