KGBNavigator is a function-based navigation library for SwiftUI that provides a scalable and type-safe way to manage navigation in your application. It uses UIKit's UINavigationController under the hood to give you precise control over the navigation stack, while allowing you to write your views in SwiftUI.
- Function-Based Navigation: Navigate using simple function calls like
navigator.navigateToProfile(userId: ...). - Compile-Time Safety: Avoid runtime errors with compile-time checks for navigation destinations and parameters.
- Scalable: Designed to support large applications with many screens and modules without a centralized router.
- Decoupled: Keeps navigation logic separate from your view logic.
- UIKit Power, SwiftUI Simplicity: Leverages
UINavigationControllerfor robust navigation andUIHostingControllerto use SwiftUI views.
The library is built around three main components:
NavigationContext: A wrapper aroundUINavigationControllerthat provides simplepush,present,pop, anddismissmethods for SwiftUI views.Navigator: A protocol that defines a navigator. Each feature or module in your app will have its own navigator.- Scoped Navigators: Concrete implementations of the
Navigatorprotocol (e.g.,HomeNavigator,ProfileNavigator) that define the specific navigation functions for a feature.
In your SceneDelegate, set up the HostingNavigationController, NavigationContext, and the initial view and navigator.
import UIKit
import SwiftUI
import KGBNavigator
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
let navController = HostingNavigationController()
let context = NavigationContext(navController: navController)
let homeNavigator = HomeNavigator(context: context)
let rootView = HomeView(navigator: homeNavigator)
navController.setViewControllers([UIHostingController(rootView: rootView)], animated: false)
window.rootViewController = navController
self.window = window
window.makeKeyAndVisible()
}
}Create a navigator for each feature module.
HomeNavigator.swift
import Foundation
import KGBNavigator
final class HomeNavigator: Navigator {
let context: NavigationContext
init(context: NavigationContext) {
self.context = context
}
func navigateToProfile(userId: UUID) {
let profileNavigator = ProfileNavigator(context: context)
let view = ProfileView(userId: userId, navigator: profileNavigator)
context.push(view)
}
}ProfileNavigator.swift
import Foundation
import KGBNavigator
final class ProfileNavigator: Navigator {
let context: NavigationContext
init(context: NavigationContext) {
self.context = context
}
func goBack() {
context.pop()
}
}Create your SwiftUI views and pass the navigator to them.
HomeView.swift
import SwiftUI
struct HomeView: View {
let navigator: HomeNavigator
var body: some View {
VStack {
Text("Home View")
.padding()
Button("Go to Profile") {
navigator.navigateToProfile(userId: UUID())
}
}
.navigationTitle("Home")
}
}ProfileView.swift
import SwiftUI
struct ProfileView: View {
let userId: UUID
let navigator: ProfileNavigator
var body: some View {
VStack {
Text("Profile View")
.padding()
Text("User ID: \(userId.uuidString)")
.padding()
Button("Go Back") {
navigator.goBack()
}
}
.navigationTitle("Profile")
}
}Add KGBNavigator as a dependency to your Package.swift file:
dependencies: [
.package(url: "https://github.com/your-username/KGBNavigator.git", from: "1.0.0")
]