How can I hide the background of an animated NavigationLink while using the swipe-to-go-back gesture?
Here's what I currently have:
and what I want it to look like:
similar to the iOS Photos app. I'm okay with covering the background using a solid color or a heavy blur, but I don't want it to be visible during the transition.
struct ContentView: View {
@Namespace private var transitionNamespace
var body: some View {
NavigationStack {
VStack {
Text("Should not be visible while swiping")
let value = "details"
NavigationLink(value: value) {
Text("Link")
.frame(width: 200, height: 50)
.background(Color.green.opacity(0.5))
.clipShape(RoundedRectangle(cornerRadius: 32))
.matchedTransitionSource(id: value, in: transitionNamespace)
}
}
.navigationDestination(for: String.self) { value in
ZStack {
Color.yellow.ignoresSafeArea(.all)
Text(value)
}
.navigationTransition(.zoom(sourceID: value, in: transitionNamespace))
.navigationBarBackButtonHidden(true)
}
}
}
}
Another small related issue why this white border come while gesture in progress? How can I fix its color
struct ContentView: View {
@Namespace private var transitionNamespace
var body: some View {
NavigationStack {
ZStack {
Color.purple.ignoresSafeArea(.all)
// .padding(-200) // this is a solution?
VStack {
Text("Should not be visible while swiping")
let value = "details"
NavigationLink(value: value) {
Text("Link")
.frame(width: 200, height: 50)
.background(Color.green.opacity(0.5))
.clipShape(RoundedRectangle(cornerRadius: 32))
.matchedTransitionSource(id: value, in: transitionNamespace)
}
}
}
.navigationDestination(for: String.self) { value in
ZStack {
Color.yellow.ignoresSafeArea(.all)
Text(value)
}
.navigationTransition(.zoom(sourceID: value, in: transitionNamespace))
.navigationBarBackButtonHidden(true)
}
}
}
}
You could try using a state variable to record whether to apply a blur or not.
.onDisappear
callback of the NavigationLink
..onDisappear
callback of the destination view. However, there is a delay before this triggers.NavigationStack
with a path
. As soon as the path goes back to empty, the flag can be reset.The blur can be applied to the full page (the VStack
in your case), or just a portion of the page, perhaps excluding the link itself. Excluding the link itself ensures that the link is always unblurred during the transition back.
@State private var isBlurred = false
@State private var path = NavigationPath()
NavigationStack(path: $path) { // 👈 modified
VStack {
Text("Should not be visible while swiping")
.blur(radius: isBlurred ? 10 : 0) // 👈 added
let value = "details"
NavigationLink(value: value) {
Text("Link")
.frame(width: 200, height: 50)
.background(Color.green.opacity(0.5))
.clipShape(RoundedRectangle(cornerRadius: 32))
.matchedTransitionSource(id: value, in: transitionNamespace)
}
.onDisappear { isBlurred = true } // 👈 added
}
.navigationDestination(for: String.self) { value in
ZStack {
Color.yellow.ignoresSafeArea(.all)
Text(value)
}
.navigationTransition(.zoom(sourceID: value, in: transitionNamespace))
.navigationBarBackButtonHidden(true)
}
}
.task(id: path) { // 👈 added
if isBlurred && path.isEmpty {
isBlurred = false
}
}