Reputation: 69
I am trying to implement enum based navigation with SwiftUINavigation framework. In my main app I try to setup deeplinking but I faced a problem with navigation links. When I change destination, the app closes the initial screen but doesn't open the new screen.
It seems NavigationLink binding nullifies the value a second time when there is already a new value. When I click Open Second Screen button on the first screen I expect it to close the first screen and open the second screen. Here is a sample code:
import SwiftUI
import SwiftUINavigation
struct ContentView: View {
enum Destination {
case first
case second
}
@State var destination: Destination?
var body: some View {
NavigationView {
VStack {
NavigationLink(
unwrapping: $destination.case(/Destination.first),
onNavigate: { isActive in
if isActive {
destination = .first
}
},
destination: { token in
NextView(buttonTitle: "Open Second View") {
destination = .second
} close: {
destination = nil
}
},
label: {
Text("Open First View")
}
)
NavigationLink(
unwrapping: $destination.case(/Destination.second),
onNavigate: { isActive in
if isActive {
destination = .second
}
},
destination: { token in
NextView(buttonTitle: "Open First View") {
destination = .first
} close: {
destination = nil
}
},
label: {
Text("Open Second View")
}
)
}
}
}
}
struct NextView: View {
let buttonTitle: String
let closure: () -> Void
let close: () -> Void
var body: some View {
VStack {
Button(buttonTitle, action: closure)
Button("Close", action: close)
}
}
}
I am using Xcode 14.2, Simulator iPhone 8 iOS 15.5
Upvotes: 0
Views: 93
Reputation: 21730
So the framework SwiftUINavigation
doesn't seem to be working for you. You are also using NavigationView
, which is deprecated.
I would suggest you try implementing it using a NavigationStack
, which works with enums natively.
Here is an example implementation. When you go from First -> Second -> First, it goes back to the previous page, instead of going deeper. This is done in the function goToTarget
. You could change the implementation if you wanted it to behave differently.
import SwiftUI
//import SwiftUINavigation
struct ContentView: View {
enum Destination {
case first
case second
}
@State private var navPath = [Destination]()
private func goBackToMenu() {
navPath.removeAll()
}
private func goToTarget(destination: Destination) {
if navPath.contains(destination) {
while !navPath.isEmpty && navPath.last != destination {
navPath.removeLast()
}
} else {
navPath.append(destination)
}
}
private var launchFirstView: some View {
NextView(
buttonTitle: "Open Second View",
closure: { goToTarget(destination: .second) },
close: goBackToMenu
)
}
private var launchSecondView: some View {
NextView(
buttonTitle: "Open First View",
closure: { goToTarget(destination: .first) },
close: goBackToMenu
)
}
var body: some View {
NavigationStack(path: $navPath) {
VStack(spacing: 20) {
NavigationLink(value: Destination.first) {
Text("Open First View")
}
NavigationLink(value: Destination.second) {
Text("Open Second View")
}
}
.navigationDestination(for: Destination.self) { destination in
switch destination {
case .first: launchFirstView
case .second: launchSecondView
}
}
}
}
}
Upvotes: 0