When I navigate backward (like swiping the view from the left), I want to be able to swipe it back from the right to move to that previous view. Sort of like an undo stack.
Is it possible to use NavigationStack
or other existing views to solve that?
It doesn't come for free, but you can implement this kind of functionality quite easily by saving the last navigation target and handling drag gestures. Like this:
struct ContentView: View {
@State private var navPath = [Int]()
@State private var previousTarget = -1
private func dragNavigate(back: Bool) -> some Gesture {
DragGesture()
.onChanged() { value in
let translation = value.translation
if abs(translation.width) > abs(translation.height) &&
back == (translation.width > 0) {
if back && navPath.count > 0 {
navPath.removeLast()
} else if !back && previousTarget >= 0 && previousTarget != navPath.last {
navPath.append(previousTarget)
}
}
}
}
private func targetView(index: Int) -> some View {
Text("View\(index + 1)")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.contentShape(Rectangle())
.gesture(dragNavigate(back: true))
}
var body: some View {
NavigationStack(path: $navPath) {
VStack(spacing: 50) {
NavigationLink("View1", value: 0)
NavigationLink("View2", value: 1)
NavigationLink("View3", value: 2)
}
.navigationDestination(for: Int.self) { index in
switch index {
case 1: targetView(index: 1)
case 2: targetView(index: 2)
default: targetView(index: 0)
}
}
.onChange(of: navPath) { newPath in
if let target = newPath.last {
previousTarget = target
}
}
}
.gesture(dragNavigate(back: false))
}
}
If the navigation hierarchy extends to more than one level then you might need to save more than one previous target, perhaps as a shadow stack.