How to share @Namespace between views

I wonder how can I share @Namespace between views to create a fluid animations between NavigationView transitions by using new matchedGeometryEffect modifier.
Answered by sarunw in 620686022
You can declare variable of Namespace.ID in a view to reference @Namespace from its parent. Here is an example.

Code Block swift
struct ContentViewNameSpace: View {
@State private var isExpanded = false
@Namespace private var namespace
var body: some View {
Group() {
if isExpanded {
VerticalView(namespace: namespace)
} else {
HorizontalView(namespace: namespace)
}
}.onTapGesture {
withAnimation {
isExpanded.toggle()
}
}
}
}
struct VerticalView: View {
var namespace: Namespace.ID
var body: some View {
VStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color.pink)
.frame(width: 60, height: 60)
.matchedGeometryEffect(id: "rect", in: namespace, properties: .frame)
Text("Hello SwiftUI!").fontWeight(.semibold)
.matchedGeometryEffect(id: "text", in: namespace)
}
}
}
struct HorizontalView: View {
var namespace: Namespace.ID
var body: some View {
HStack {
Text("Hello SwiftUI!").fontWeight(.semibold)
.matchedGeometryEffect(id: "text", in: namespace)
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color.pink)
.frame(width: 60, height: 60)
.matchedGeometryEffect(id: "rect", in: namespace, properties: .frame)
}
}
}


Accepted Answer
You can declare variable of Namespace.ID in a view to reference @Namespace from its parent. Here is an example.

Code Block swift
struct ContentViewNameSpace: View {
@State private var isExpanded = false
@Namespace private var namespace
var body: some View {
Group() {
if isExpanded {
VerticalView(namespace: namespace)
} else {
HorizontalView(namespace: namespace)
}
}.onTapGesture {
withAnimation {
isExpanded.toggle()
}
}
}
}
struct VerticalView: View {
var namespace: Namespace.ID
var body: some View {
VStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color.pink)
.frame(width: 60, height: 60)
.matchedGeometryEffect(id: "rect", in: namespace, properties: .frame)
Text("Hello SwiftUI!").fontWeight(.semibold)
.matchedGeometryEffect(id: "text", in: namespace)
}
}
}
struct HorizontalView: View {
var namespace: Namespace.ID
var body: some View {
HStack {
Text("Hello SwiftUI!").fontWeight(.semibold)
.matchedGeometryEffect(id: "text", in: namespace)
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color.pink)
.frame(width: 60, height: 60)
.matchedGeometryEffect(id: "rect", in: namespace, properties: .frame)
}
}
}


Passing animation namespaces across NavigationView transitions is not possible as of Xcode 12 beta 2, but this might change in the future. The same is also true for sheets.

More generally, when you use @Namespace the property you create automatically has the type Namespace.ID, which you pass between views freely. For example, in your parent view (the one hosting whatever views you are animating), you might start by creating a namespace like this: @Namespace var animation. You could then create separate SwiftUI views that store an externally injected namespace like this:
Code Block
struct ChildView: View {
let animation: Namespace.ID
}
And finally you can pass the parent namespace into the child for use with matchedGeometryEffect() like this:
Code Block
ChildView(animation: animation)

This way multiple independent SwiftUI views can share the same animation namespace.
How to share @Namespace between views
 
 
Q