SwiftUI is great. But navigation isn't.
FlowKit is a lightweight UIKit-backed navigation helper for SwiftUI.
| Platform | Minimum Swift Version | Installation |
|---|---|---|
| iOS 13.0+ | 5.5 | Swift Package Manager |
File->Add Packages...And paste the repository URL.- Or add it to the
dependenciesvalue of yourPackage.swift.
dependencies: [
.package(url: "https://github.com/Mercen-Lee/FlowKit.git", .branch("main"))
]- Push View
flow.push(NextView())
// or
flow.push(NextView(), animated: false)
// Preserve a tab bar when pushing inside tab-based apps.
flow.push(NextView(), preserveTabBar: true)
flow.tabPush(NextView())- Pop View
flow.pop()
flow.pop(3) // Removes up to 3 views, clamped at the root view.- Pop View to Root
flow.popToRoot()- Replace Views
flow.replace([StepView(index: 1), StepView(index: 2)])
// Heterogeneous view types can use the builder, variadic overloads, or AnyView.
flow.replace {
FirstView()
SecondView()
}
flow.replace(FirstView(), SecondView())
flow.replace([AnyView(FirstView()), AnyView(SecondView())])- Switch Views
flow.switchToView(at: 0)
flow.moveView(from: 0, to: 2)
flow.moveTopView(to: 0)- Reload View
flow.reload()- Navigation Bar
FlowPresenter(rootView: ContentView(), navigationBarHidden: true)
flow.hideNavigationBar()
flow.showNavigationBar()- Present Sheet
flow.sheet(SheetView())
flow.fullScreenCover(FullScreenView())- Present Alert
let alert = Alert(title: "Error",
message: "Not Found",
dismissButton: .default("Ok"))
flow.alert(alert)- Deep Link
flow.registerDeepLink(.init(path: "/details") { url, flow in
flow.push(DetailView())
})
flow.openDeepLink(URL(string: "myapp://host/details")!)import SwiftUI
import FlowKit
@main
struct SampleApp: App {
var body: some Scene {
WindowGroup {
FlowPresenter(rootView: ContentView())
}
}
}struct ContentView: View {
@Flow var flow
var body: some View {
Button {
flow.push(NextView())
} label: {
Text("Push")
}
}
}
struct NextView: View {
@Flow var flow
var body: some View {
Button {
flow.pop()
} label: {
Text("Pop")
}
}
}FlowPresenter injects FlowProvider through a weak environment value, so pushed
SwiftUI views can use @Flow without retaining the provider as an
EnvironmentObject.
FlowPresenter keeps the backing provider alive with SwiftUI state, which avoids resetting the navigation controller when the presenter view is rebuilt. Navigation commands target the active navigation controller, including the selected tab when FlowKit is embedded in a tab bar. Sheets, full-screen covers, and alerts are presented from the top-most visible view controller.
FlowKit depends on UIKit, so build it for an iOS destination instead of running a
plain macOS swift test.
xcodebuild -scheme FlowKit -destination 'generic/platform=iOS' CODE_SIGNING_ALLOWED=NO buildTCA Example
struct FlowDependency: DependencyKey {
static var liveValue: FlowProvider {
FlowProvider(rootView: ContentView())
}
}
extension DependencyValues {
var flow: FlowProvider {
get { self[FlowDependency.self] }
set { self[FlowDependency.self] = newValue }
}
}struct Content: Reducer {
@Dependency(\.flow) var flow
...
}