/Routing

Routing library for abstracting navigation logic from SwiftUI views.

Primary LanguageSwiftMIT LicenseMIT

Description

Routing is a library for separating navigation logic from SwiftUI views.

  • De-couples navigation logic from SwiftUI views.
  • Leads to better separation of concerns

Requirements

  • Requires iOS 16 or later.

Installation

You can install Routing using the Swift Package Manager.

  1. In Xcode, select "File" > "Add Packages...".
  2. Copy & paste the following into the "Search or Enter Package URL" search bar.
https://github.com/obvios/Routing.git
  1. Xcode will fetch the repository & the "Routing" library will be added to your project.

Getting Started

  1. Create a Routable conforming Enum to represent the different views you wish to route to.
import SwiftUI
import Routing

enum ExampleRoute: Routable {
    case viewA
    case viewB(String)
    case viewC
    
    @ViewBuilder
    func viewToDisplay(router: Router<ExampleRoute>) -> some View {
        switch self {
        case .viewA:
            ViewA(router: router)
        case .viewB(let description):
            ViewB(router: router, description: description)
        case .viewC:
            ViewC(router: router)
        }
    }
    
    var navigationType: NavigationType {
        switch self {
        case .viewA:
            return .push
        case .viewB(_):
            return .sheet
        case .viewC:
            return .fullScreenCover
        }
    }
}
  1. Wrap your view hierarchy in a RoutingView that is initialized with your Routable enum. It will inject a Router instance into your root view.
import SwiftUI
import Routing

struct ContentView: View {
    var body: some View {
        RoutingView(ExampleRoute.self) { router in
            RootView(router: router)
        }
    }
}

struct RootView: View {
    @StateObject var router: Router<ExampleRoute>
    
    init(router: Router<ExampleRoute>) {
        _router = StateObject(wrappedValue: router)
    }
    
    var body: some View {
        VStack() {
            Button("View A") {
                router.routeTo(.viewA)
            }
            Button("View B") {
                router.routeTo(.viewB("Got here from RootView"))
            }
            Button("View C") {
                router.routeTo(.viewC)
            }
        }
    }
}
  1. Use the Router functions from any of your views. Here is ViewA which is pushed onto the navigation stack by RootView.
struct ViewA: View {
    @StateObject var router: Router<ExampleRoute>
    
    init(router: Router<ExampleRoute>) {
        _router = StateObject(wrappedValue: router)
    }
    
    var body: some View {
        Text("View A")
        Button("ViewC") {
            router.routeTo(.viewC)
        }
        Button("Dismiss") {
            router.dismiss()
        }
    }
}

Additional Resources

The below articles are from my blog series explaining the Router pattern and documents the progress of this library.