A single .glassEffect() looks right in isolation, but place several glass views next to each other — a row of toolbar buttons, a segmented control — and each one samples only its own small patch of background. The result is a row of mismatched glass blobs instead of one continuous material, because glass cannot sample other glass.
#The new way
struct ExpandingToolbar: View {
@Namespace private var namespace
@State private var isExpanded = false
var body: some View {
GlassEffectContainer(spacing: 20) {
HStack(spacing: 20) {
Button {
withAnimation(.smooth) { isExpanded.toggle() }
} label: {
Image(systemName: "plus")
.frame(width: 44, height: 44)
}
.glassEffect(.regular.interactive(), in: .circle)
.glassEffectID("trigger", in: namespace)
if isExpanded {
ForEach(["pencil", "eraser", "trash"], id: \.self) { icon in
Button {
} label: {
Image(systemName: icon)
.frame(width: 44, height: 44)
}
.glassEffect(.regular.interactive(), in: .circle)
.glassEffectID(icon, in: namespace)
}
}
}
.padding(.horizontal)
}
}
}
Toggling isExpanded animates the new buttons in while the whole row keeps a shared, consistent glass appearance.
#Why it matters
GlassEffectContainergives every glass view inside it a shared sampling region, so a group of controls reads as one material instead of separate blobs.glassEffectID(_:in:)paired with a shared@Namespacelets a glass view morph into a differently shaped or positioned one across a state change — the glass equivalent ofmatchedGeometryEffect- The container's
spacingparameter should match the actual layout spacing, or the rendered glass gaps look wrong
#Gotcha
This is very new API and still settling — verify the exact GlassEffectContainer initializer and GlassEffectStyle surface against current Apple docs before shipping anything beyond the basics shown here. One confirmed requirement: morphing only happens when both the old and new view share the same glassEffectID value, the same @Namespace, and are both inside the same GlassEffectContainer instance — put either view outside that container and it pops instead of morphing.