The lightweight navigation framework for SwiftUI.
sRouting using the native navigation mechanism in SwiftUI.
It's easy to handle navigation between screens by sRouting.
The Router
can trigger a transition from inside(view) or outside(view model) the view.
- iOS 17 or above
- Xcode 15 or above
Explore DocC to find the rich tutorials and getting started with sRouting. See this WWDC presentation about more information.
From xCode select Product -> Build Doccumentation -> Explore.
Or downloads the doccument archive from release
Add sRouting
as a dependency to the project.
See this WWDC presentation about more information how to adopt Swift packages in your app.
Specify https://github.com/ThangKM/sRouting.git
as the sRouting
package link.
Set up SRRootView
and working with sRouter(_:)
Create your root view with SRRootView
.
Declares your SRRoute
.
Working with sRContext(tabs:stacks:)
macro, ScreenView
and sRouter(_:)
macro.
To create a route we have to conform to the SRRoute
Protocol.
enum HomeRoute: SRRoute {
case pastry
case cake
var path: String {
swich self {
case .pastry: return "pastry"
case .cake: return "cake"
}
}
var screen: some View {
switch self {
case .pastry: PastryScreen()
case .cake: CakeScreen()
}
}
}
Setup a context and SRRootView
for your app
Declaring Context:
@sRContext(tabs: ["home", "setting"], stacks: "home", "setting")
struct SRContext { }
Declaring View of navigation destination:
@sRouteObserve(HomeRoute.self, SettingRoute.self)
struct ObserveView<Content>: View where Content: View { }
Setup Your App:
@main
struct BookieApp: App {
let context = SRContext()
...
var body: some Scene {
WindowGroup {
SRRootView(context: context) {
SRTabbarView {
SRNavigationStack(path: context.homePath, observeView: ObserveView.self) {
AppRoute.home.screen
}.tabItem {
Label("Home", systemImage: "house")
}.tag(SRTabItem.home.rawValue)
SRNavigationStack(path: context.settingPath, observeView: ObserveView.self) {
AppRoute.setting.screen
}.tabItem {
Label("Setting", systemImage: "gear")
}.tag(SRTabItem.setting.rawValue)
}
.onDoubleTapTabItem { ... }
.onTabSelectionChange { ... }
}
.onOpenURL { url in
Task {
...
await context.routing(.resetAll,.select(tabItem: .home),
.push(route: HomeRoute.cake, into: .home))
}
}
}
}
}
Build a screen with ScreenView
, ScreenView
will create a hidden NavigatorView at below content view
in a ZStack.
The NavigatorView will handle transactions that are emited by Router
enum HomeRoute: SRRoute {
case detail
...
}
@sRouter(HomeRoute.self)
class HomeViewModel { ... }
struct HomeScreen: View {
@Environment(\.dismiss)
private var dismissAction
@State let viewModel = HomeViewModel()
var body: some View {
ScreenView(router: viewModel, dismissAction: dismissAction) {
...
}
}
To navigate to a screen that must be in HomeRoute
we use the trigger(to:with:)
function in the Router
DeepLink:
...
.onOpenURL { url in
Task {
...
await context.routing(.resetAll,.select(tabItem: .home),
.push(route: HomeRoute.cake, into: .home))
}
}
Push:
router.trigger(to: .cake, with: .push)
NavigationLink:
NavigationLink(route: HomeRoute.pastry) {
...
}
Present full screen:
router.trigger(to: .cake, with: .present)
Sheet:
router.trigger(to: .cake, with: .sheet)
To show an alert we use the show(alert:)
function.
router.show(alert: Alert.init(title: Text("Alert"),
message: Text("Message"),
dismissButton: .cancel(Text("OK")))
To show an error message we use the show(error:and:)
function.
router.show(error:NetworkingError.lossConnection)
To dismiss a screen we use the dismiss()
function.
router.dismiss()
To dismiss to root view we use the dismissAll()
function.
Required the root view is a SRRootView
router.dismissAll()
To seclect the Tabbar item we use the selectTabbar(at:)
function.
router.selectTabbar(at:0)
sRouting also supported pop, pop to root and pop to a target function for the NavigationView
router.pop()
router.popToRoot()
router.pop(to: HomeRoute.cake)
sRouting is a lightweight framework and flexiable.
sRouting
is released under an MIT license. See License.md for more information.