Last active
February 22, 2023 21:39
-
-
Save benbacardi/92e6eec1d97204280f9dd3bc387a82f3 to your computer and use it in GitHub Desktop.
Playing with "global router-style" navigation in SwiftUI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ContentView.swift | |
// AppRouterPlayground | |
// | |
// Created by Ben Cardy on 22/02/2023. | |
// | |
import SwiftUI | |
enum Route: Hashable { | |
case firstDestination | |
case secondDestinationWithID(id: String) | |
} | |
@MainActor | |
class RoutePath: ObservableObject { | |
@Published var path: [Route] = [] | |
public func navigate(to route: Route) { | |
path.append(route) | |
} | |
public func replace(with routes: [Route]) { | |
path = routes | |
} | |
} | |
struct FirstDestination: View { | |
@EnvironmentObject var routePath: RoutePath | |
var body: some View { | |
ScrollView { | |
Text("First Destination") | |
Button(action: { | |
routePath.navigate(to: .secondDestinationWithID(id: "ID 2")) | |
}) { | |
Text("Go To Second Destination") | |
} | |
} | |
.navigationTitle("First Destination") | |
} | |
} | |
struct SecondDestination: View { | |
@EnvironmentObject var routePath: RoutePath | |
let id: String | |
var body: some View { | |
ScrollView { | |
Text("Second Destination: \(id)") | |
Button(action: { | |
routePath.navigate(to: .firstDestination) | |
}) { | |
Text("Go To First Destination") | |
} | |
Button(action: { | |
routePath.replace(with: [.firstDestination, .firstDestination]) | |
}) { | |
Text("Replace!") | |
} | |
} | |
.navigationTitle("Second \(id)") | |
} | |
} | |
@MainActor | |
extension View { | |
func withAppRouter() -> some View { | |
navigationDestination(for: Route.self) { destination in | |
switch destination { | |
case .firstDestination: | |
FirstDestination() | |
case let .secondDestinationWithID(id): | |
SecondDestination(id: id) | |
} | |
} | |
} | |
} | |
struct TabOne: View { | |
@StateObject private var routePath = RoutePath() | |
var body: some View { | |
NavigationStack(path: $routePath.path) { | |
ScrollView { | |
Text("Tab One") | |
Button(action: { | |
routePath.navigate(to: .firstDestination) | |
}) { | |
Text("Go To First Destination") | |
} | |
Button(action: { | |
routePath.navigate(to: .secondDestinationWithID(id: "ID 1")) | |
}) { | |
Text("Go To Second Destination") | |
} | |
} | |
.navigationTitle("Tab One") | |
.withAppRouter() | |
} | |
.environmentObject(routePath) | |
} | |
} | |
struct ContentView: View { | |
var body: some View { | |
TabView { | |
TabOne() | |
.tag(1) | |
.tabItem { | |
Label("Tab One", systemImage: "1.circle") | |
} | |
TabOne() | |
.tag(2) | |
.tabItem { | |
Label("Tab Two", systemImage: "2.circle") | |
} | |
} | |
} | |
} | |
struct ContentView_Previews: PreviewProvider { | |
static var previews: some View { | |
ContentView() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment