Routing
is a lightweight SwiftUI navigation library.
- Leverages 1st-party APIs
NavigationStack
&NavigationDestination
. - Never be confused about
NavigationLink
orNavigationPath
again! (You don't need them) - Type-Safe Navigation (better performance than type-erasing).
- Centralized Navigation Logic.
- Dynamic Navigation Stack Management.
- Unit Tested protocol implementations.
- Zero 3rd party dependencies.
- Documentation
Note - This library is for NavigationStack only.
If you need to abstract sheets, alerts, etc. then use my other library Presenting
Platform | Minimum Version |
---|---|
iOS | 16.0 |
macOS | 13.0 |
tvOS | 16.0 |
watchOS | 9.0 |
You can install Routing
using the Swift Package Manager.
- In Xcode, select
File
>Add Package Dependencies
.
- Copy & paste the following into the
Search or Enter Package URL
search bar.
https://github.com/JamesSedlacek/Routing.git
- Xcode will fetch the repository & the
Routing
library will be added to your project.
- Create a
Route
enum that conforms to theRoutable
protocol.
import Routing
import SwiftUI
enum ExampleRoute: Routable {
case detail
case settings
var body: some View {
switch self {
case .detail:
DetailView()
case .settings:
SettingsView()
}
}
}
- Create a
Router
object and wrap yourRootView
with aRoutingView
.
import SwiftUI
import Routing
struct ContentView: View {
@StateObject private var router: Router<ExampleRoute> = .init()
var body: some View {
RoutingView(stack: $router.stack) {
Button("Go to Settings") {
router.navigate(to: .settings)
}
}
}
}
- Handle navigation using the
Router
functions
/// Navigate back in the stack by a specified count.
func navigateBack(_ count: Int)
/// Navigate back to a specific destination in the stack.
func navigateBack(to destination: Destination)
/// Navigate to the root of the stack by emptying it.
func navigateToRoot()
/// Navigate to a specific destination by appending it to the stack.
func navigate(to destination: Destination)
/// Navigate to multiple destinations by appending them to the stack.
func navigate(to destinations: [Destination])
/// Replace the current stack with new destinations.
func replace(with destinations: [Destination])
import Routing
import SwiftUI
enum ContentRoute: Routable {
case detail(Color)
case settings
var body: some View {
switch self {
case .detail(let color):
ColorDetail(color: color)
case .settings:
SettingsView()
}
}
}
struct ContentView: View {
@StateObject private var router: Router<ContentRoute> = .init()
private let colors: [Color] = [.red, .green, .blue]
var body: some View {
RoutingView(stack: $router.stack) {
List(colors, id: \.self) { color in
color
.onTapGesture {
router.navigate(to: .detail(color))
}
}
}
}
}
struct ColorDetail: View {
private let color: Color
init(color: Color) {
self.color = color
}
var body: some View {
color.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
The RoutingView
essentially is just wrapping your view with a NavigationStack
& navigationDestination
.
NavigationStack(path: $routes) {
root()
.navigationDestination(for: Routes.self) { view in
view
}
}