10

How to define custom environment values in SwiftUI

 2 years ago
source link: https://sarunw.com/posts/how-to-define-custom-environment-values-in-swiftui/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

How to define custom environment values in SwiftUI

30 Aug 2021 ⋅ 4 min read ⋅ SwiftUI

Table of Contents

One of a mechanism that SwiftUI use to pass data from one view to another is via @Environment. We learn how SwiftUI use the environment to pass value such as locale and calendar through a view hierarchy in What is @Environment in SwiftUI. In that article, I only mentioned how to read an environment value from the system predefined EnvironmentValues, but it is possible to define your own custom keys/values and that is what we are going to learn in this article.

To define Environment values you need two things.

git-tower.png

Meet isSensitive

As a demonstration, we will create a new value called isSensitive. This value indicates whether the view is considered sensitive. We will use this to make sure we hide sensitive information within a view.

Create an environment key

First, you need to define a new key for your new value. You do that by creating a type that conforms to the EnvironmentKey protocol. The only requirement for this protocol is you define a default value for the key.

private struct SensitiveKey: EnvironmentKey {
// 1
static let defaultValue: Bool = false
}

1 Declare a new key with a default value of false.

Even it has a word key in the name (EnvironmentKey), this is where you declare your data type. In this case, we declare boolean environment data, which you can access it using the SensitiveKey key.

Introduce new value to EnvironmentValues

Once we declare a data type and a key to access it, we introduce this newly create key/value to EnvironmentValues using an extension. We use the key defined in the last section to get and set the value.

extension EnvironmentValues {
var isSensitive: Bool {
get { self[SensitiveKey.self] }
set { self[SensitiveKey.self] = newValue }
}
}

This is a boilerplate code for adding a new value to EnvironmentValues. Just create a new variable environment value and use the key you created to access the value in getter and setter.

Add a dedicated modifier (Optional)

After creating a new key and introduce it to environmental values, we have a working environment value that you can set and access like the system-defined one.

struct ContentView: View {
@Environment(\.isSensitive) var isSensitive

var body: some View {
Text("Hello")
.environment(\.isSensitive, true)
}
}

You can add a dedicated modifier to make it easier for users to set the new value. To do that we create a new view modifier and wrap .environment(\.isSensitive) inside.

extension View {
func isSensitive(_ value: Bool) -> some View {
environment(\.isSensitive, value)
}
}

This gives a more concise syntax to override the environment value, just like some system-defined ones such as .font and .colorScheme.

Text("Hello")
.isSensitive(true)

Before wrapping up, let's put this new value into use. We create a PasswordField that can react to the change of the isSensitive value.

struct PasswordField: View {
let password: String

// 1
@Environment(\.isSensitive) private var isSensitive

var body: some View {
HStack {
Text("Password")
Text(password)
.redacted(reason: isSensitive ? .placeholder: []) // 2
}
}
}

1 We read environment value with @Environment.
2 View then react to isSensitive value by redact the password if isSensitive is true.

Then we put this into use.

struct ContentView: View {
// 1
@State private var isSensitive = false

var body: some View {
VStack {
// 2
Toggle("Sensitive", isOn: $isSensitive)
// 3
PasswordField(password: "123456")
.isSensitive(isSensitive)
}.padding()
}
}

1 We create a @State variable to control isSensitive environment value.
2 Bind the state variable to a toggle, so we can control the value.
3 Use the state variable to override isSensitive environment value of PasswordField.

Here is the result.

Set isSensitive to true will hide sensitive data.Set isSensitive to true will hide sensitive data.

You can easily support sarunw.com by checking out this sponsor.

git-tower.png

Conclusion

It might not be obvious that we can create a custom environment value, but we can do that. The steps to create one are not as straightforward as we usually do, but it isn't hard if you know how to do it.

Here is a summary of how to create a new environment value.

// Create an environment key
private struct NewKey: EnvironmentKey {
    static let defaultValue: DataTypeForNewValue = defaultValue
}

// ## Introduce new value to EnvironmentValues
extension EnvironmentValues {
    var newEnvironmentName: DataTypeForNewValue {
        get { self[NewKey.self] }
        set { self[NewKey.self] = newValue }
    }
}

// Add a dedicated modifier (Optional)
extension View {
    func newModifier(_ value: DataTypeForNewValue) -> some View {
        environment(\.newEnvironmentName, value)
    }
}

We use private access for EnvironmentKey since we only use this key in our internal boilerplate code. Others will reference this value through the environment value name.


You may also like

What is @Environment in SwiftUI

Learn how SwiftUI shares application settings and preference values across the app.

SwiftUI
Make a placeholder view in SwiftUI with redacted()

SwiftUI provides an easy way to convert to render any view into a placeholder style by redacting its content.

SwiftUI
How to fix ZStack's views disappear transition not animated in SwiftUI

Show and hide transition animation in ZStack can be glitchy. Learn how to fix it with a simple trick.

SwiftUI

Read more article about SwiftUI

or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron

Buy me a coffee

Tweet

Share

Previous
How to reference a method with the same name and parameters but a different return type in Swift

Trying to reference two methods with the same name and parameters will cause an ambiguous compile error. Learn how to resolve it.

Next
How to set custom CodingKey for the convertFromSnakeCase decoding strategy

The thing you should know before using the convertFromSnakeCase decoding strategy.

← Home


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK