Router-SwiftUIWorkaround

Workaround for https://www.swiftuiseries.com/workarounds

2022-05-24.12.52.00.mov

About

SwiftUI does not allow programmable screen navigation out of the box, has many bugs and limited screen manipulation capabilities. This repository provides a workaround to use routing programmatically.

Steps to use

  1. Configure routes Use enum for routes and dont forget to choose screens with NavigationView!

enum ScreenRoute: ScreenProtocol {
    case start
    case navigator
    case fullScreen
    case sheetScreen
    
    var embedInNavView: Bool {
        switch self {
        case .start, .sheetScreen:
            return true
        case .navigator, .fullScreen:
            return false
        }
    }
}
  1. Create router factory. This class maps routes and creates views.

class ScreenRouterFactory: RouterFactory {
    
    @ViewBuilder func makeBody(for screen: ScreenRoute) -> some View {
        switch screen {
        case .start:
            StartingView()
        case .navigator:
            RoutesView()
        case .fullScreen:
            FullScreenView()
        case .sheetScreen:
            SheetView()
        }
    }
}
  1. (? optional) Create typealias for easy naming Routers.
typealias ScreenRouter = Router<ScreenRoute, ScreenRouterFactory>
  1. Create Router instance. You can create in Views, ViewModels or use in DI. Don’t forget to use @StateObject or similar wrappers in views for re-render
let screenRouter = ScreenRouter(rootScreen: .start, factory: ScreenRouterFactory())
  1. Use it! Start routing with start method. In this example EnvObject used:

struct MainView: View {
    @EnvironmentObject var screenRouter: ScreenRouter
    
    var body: some View {
        screenRouter.start()
    }
}
  1. Available Router’s methods:

func start() -> some View
func presentSheet(_ screen: ScreenType)
func dismissLast()
func navigateTo(_ screen: ScreenType)
func presentFullScreen(_ screen: ScreenType)
func popToRoot()

GitHub

View Github