Spatial SwiftUI: glassBackgroundEffect

We can use this to add a glass background to any view.

Overview

I’m sure we all know how to add this modifier to any view to add a glass background. This is helpful for plane windows, volumes, ornaments, and attachments.

VStack {...}
.glassBackgroundEffect()

But it doesn’t stop there. This seemingly simple modifier has some powerful features. Consider this simple view hierarchy.

  • VStack
    • HStack
      • Card View
      • Model View
    • HStack
      • Card View
      • Model View

We could add.glassBackgroundEffect to the VStack and call it a day. That would wrap our view much like any default window in visionOS. What if we want to hide the glass on the VStack, but show it on the HStacks? We can use the .implicit display mode. This will only add the effect to a view when glass is not present further up the hierarchy.

.glassBackgroundEffect(.automatic, displayMode: .implicit)

This can cascade several levels deep. For example, we can show a glass effect on a model view when neither the parent HStack or VStack have glass.

VStackLayout().depthAlignment(alignment) {
    ...
    HStackLayout().depthAlignment(alignment) {        
        ModelViewSimple(name: "Earth", bundle: realityKitContentBundle)
            .frame(width: 150, height: 150)
            .padding(6)
            .glassBackgroundEffect(.automatic, displayMode: .implicit)
    }
}

The most common effect we use is .plate. But we can also use .feathered, which can be customized. For example, if we want featured background for a title.

Text("Feathered Glass Background Effect")
  .font(.extraLargeTitle)
  .glassBackgroundEffect(.feathered(padding: 36, softEdgeRadius: 3), displayMode: .always)
Feathered title

We can also shape the effect using an InsettableShape. Here we have a plate effect with a circle shape.

Text("Moon")
  .font(.extraLargeTitle)
  .padding(48)
  .glassBackgroundEffect(.plate, in: .circle, displayMode: .always)
Circle shaped plate

Let’s see this all in action.

Glass background demo video

Example Code

struct Example103: View {

    @State private var parentBackgroundFeathered: Bool = false
    @State private var parentBackgroundMode: GlassBackgroundDisplayMode = .always
    @State private var childrenBackgroundMode: GlassBackgroundDisplayMode = .implicit

    var alignment: DepthAlignment = .back

    var body: some View {

        /// Feathered Example
//        Text("Feathered Glass Background Effect")
//            .font(.extraLargeTitle)
//            .glassBackgroundEffect(.feathered(padding: 36, softEdgeRadius: 3), displayMode: .always)

        /// Clip Shape Example
//        Text("Moon")
//            .font(.extraLargeTitle)
//            .padding(48)
//            .glassBackgroundEffect(.plate, in: .circle, displayMode: .always)

        /// Layout Example
        VStackLayout().depthAlignment(alignment) {

            HStackLayout().depthAlignment(alignment) {

                earthCard

                ModelViewSimple(name: "Earth", bundle: realityKitContentBundle)
                    .frame(width: 150, height: 150)
                    .padding(6)
                    .glassBackgroundEffect(.automatic, displayMode: .implicit)

            }
            .padding()
            .glassBackgroundEffect(.automatic, displayMode: childrenBackgroundMode)

            HStackLayout().depthAlignment(alignment) {

                ModelViewSimple(name: "Moon", bundle: realityKitContentBundle)
                    .frame(width: 60, height: 60)
                    .padding(6)
                    .glassBackgroundEffect(.automatic, displayMode: .implicit)

                moonCard
            }
            .padding()
            .glassBackgroundEffect(.automatic, displayMode: childrenBackgroundMode)

        }
        .glassBackgroundEffect(.automatic, displayMode: parentBackgroundMode)

        // Controls to modify the example
        .ornament(attachmentAnchor: .scene(.trailing), contentAlignment: .trailing, ornament: {
            VStack(alignment: .center, spacing: 8) {
                Text("VStack")
                Button(action: {
                    parentBackgroundMode = .always
                }, label: {
                    Text("Always")
                })
                Button(action: {
                    parentBackgroundMode = .never
                }, label: {
                    Text("Never")
                })
                Text("HStacks")
                Button(action: {
                    childrenBackgroundMode = .implicit
                }, label: {
                    Text("Implicit")
                })

                Button(action: {
                    childrenBackgroundMode = .never
                }, label: {
                    Text("Never")
                })
            }
            .padding()
            .controlSize(.small)
            .glassBackgroundEffect()

        })

    }

    var earthCard: some View {
        VStack {
            Text("Earth")
                .font(.title)
            Text("The only known planet known to serve ice cream.")
                .font(.caption)
        }
        .padding()
        .background(.black)
        .cornerRadius(24)
        .shadow(radius: 20)
        .frame(width: 220, height: 160)
    }

    var moonCard: some View {
        VStack {
            Text("Luna")
                .font(.title)
            Text("Made amost entirely of cheese.")
                .font(.caption)
        }
        .padding()
        .background(.black)
        .cornerRadius(24)
        .shadow(radius: 20)
        .frame(width: 180, height: 140)
    }
}

Support our work so we can continue to bring you new examples and articles.

Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Questions or feedback?