Contents

ContainerValueKey

A key for accessing container values.

Declaration

protocol ContainerValueKey

Overview

You can create custom container values by extending the ContainerValues structure with new properties. First declare a new container value key type and specify a value for the required defaultValue property:

private struct MyContainerValueKey: ContainerValueKey {
    static let defaultValue: String = "Default value"
}

The Swift compiler automatically infers the associated Value type as the type you specify for the default value. Then use the key to define a new container value property:

extension ContainerValues {
    var myCustomValue: String {
        get { self[MyContainerValueKey.self] }
        set { self[MyContainerValueKey.self] = newValue }
    }
}

Clients of your container value never use the key directly. Instead, they use the key path of your custom container value property. To set the container value for a view, add the containerValue(_:_:) view modifier to that view:

MyView()
    .containerValue(\.myCustomValue, "Another string")

As a convenience, you can also define a dedicated view modifier to apply this container value:

extension View {
    func myCustomValue(_ myCustomValue: String) -> some View {
        containerValue(\.myCustomValue, myCustomValue)
}

This improves clarity at the call site:

MyView()
    .myCustomValue("Another string")

To read the container value, use Group(subviews:) on a containing view, and then access the container value on members of that collection.

@ViewBuilder var content: some View {
    Text("A").myCustomValue("Hello")
    Text("B").myCustomValue("World")
}

Group(subviews: content) { subviews in
    ForEach(subviews) { subview in
        Text(subview.containerValues.myCustomValue)
    }
}

In practice, this will mostly be used by views that contain multiple other views to extract information from their subviews. You could turn the example above into such a container view as follows:

struct MyContainer<Content: View>: View {
    var content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        Group(subviews: content) { subviews in
            ForEach(subviews) { subview in
                // Display each view side-by-side with its custom value.
                HStack {
                    subview
                    Text(subview.containerValues.myCustomValue)
                }
            }
        }
    }
}

Topics

Associated Types

Type Properties

See Also

Accessing a container’s subviews