I’ve abstracted my navigation into a service for my SwiftUI app. When I run it on the simulator or physical device it works perfectly. However, when testing in the #Preview
, the navigation doesn’t seem to work.
I understand there are some limitations, but is there a way I could potentially create a Swift NavigationStack preview wrapper (for only in #Preview
) so that if I wanted to test certain screens I could also test the navigation?
At the moment I can only preview one screen at a time, but have to keep a simulator running for navigation flow. For proper testing that’s okay, but when building or testing a UI flow I like the preview.
I’m currently running Xcode 15.4.0.
This is some bare minimum code to demonstrate:
protocol NavigationRouteRepresentable: Hashable {
associatedtype Body: View
@ViewBuilder @MainActor var body: Self.Body { get }
}
enum Route: NavigationRouteRepresentable {
case settings
var body: some View {
switch self {
case .settings:
Text("Settings")
}
}
}
final class RouteManager<Route: NavigationRouteRepresentable>: ObservableObject {
@Published var routes: NavigationPath
init() { self.routes = NavigationPath() }
func push(to screen: Route) { routes.append(screen) }
}
struct NavigationWrapper: View {
@StateObject
private var routeManager: RouteManager<Route> = .init()
var body: some View {
NavigationStack(path: $routeManager.routes) {
ContentView()
.environmentObject(routeManager)
}
.navigationDestination(for: Route.self) { destination in
destination.body
.environmentObject(routeManager)
}
}
}
struct ContentView: View {
@EnvironmentObject
private var routeManager: RouteManager<Route>
var body: some View {
Text("Hello World")
.toolbar {
Button("Go") {
routeManager.push(to: .settings)
}
}
}
}
#Preview {
@StateObject var routeManager: RouteManager<Route> = .init()
return NavigationStack(path: $routeManager.routes) {
ContentView()
.environmentObject(routeManager)
}
}