✨ LinkNavigator is a library that helps you easily navigate between pages in SwiftUI.
The following translations of this README have been contributed by members of the community:
If you'd like to contribute a translation, please open a PR with a link to a Gist!
push one or many pages.
navigator.next(paths: ["page1", "page2"], items: [:], isAnimated: true)
pop one or many pages.
navigator.remove(paths: ["pageToRemove"])
back to the prior page or dismiss modal simply.
navigator.back(isAnimated: true)
go to the page you want. If that page is already within navigation stack, go back to that page. Else if that page is not within stack, push new one.
navigator.backOrNext(path: "targetPage", items: [:], isAnimated: true)
replace current navigation stack with new one.
navigator.replace(paths: ["main", "depth1", "depth2"], items: [:], isAnimated: true)
open page as sheet or full screen cover.
navigator.sheet(paths: ["sheetPage"], items: [:], isAnimated: true)
navigator.fullSheet(paths: ["page1", "page2"], items: [:], isAnimated: true, prefersLargeTitles: false)
close a modal and call completion closure.
navigator.close(isAnimated: true) { print("modal dismissed!") }
show a system alert.
let alertModel = Alert(
title: "Title",
message: "message",
buttons: [.init(title: "OK", style: .default, action: { print("OK tapped") })],
flagType: .default)
navigator.alert(target: .default, model: alertModel)
edit complicated paths and use it.
// current navigation stack == ["home", "depth1", "depth2", "depth3"]
// target stack == ["home", "depth1", "newDepth"]
var new = navigator.range(path: "depth1") + ["newDepth"]
navigator.replace(paths: new, items: [:], isAnimated: true)
control pages behind modal.
navigator.rootNext(paths: ["targetPage"], items: [:], isAnimated: true)
navigator.rootBackOrNext(path: "targetPage", items: [:], isAnimated: true)
you can choose modal presentation styles for iPhone and iPad respectively.
navigator.customSheet(
paths: ["sheetPage"],
items: [:],
isAnimated: true,
iPhonePresentationStyle: .fullScreen,
iPadPresentationStyle: .pageSheet,
prefersLargeTitles: .none)
forcely reload the last page behind the modal. This is useful when you need to call the onAppear(perform:) again.
navigator.rootReloadLast(items: [:], isAnimated: false)
LinkNavigator provides 2 Example Apps.
To install LinkNavigator in your SwiftUI project, you need to implement 4 files.
You can freely edit the type names. In the following examples, simple names are used for clarity.
Describe in order: AppDependency -> AppRouterGroup -> AppDelegate -> AppMain
// AppDependency.swift
// A type that manages external dependencies.
import LinkNavigator
struct AppDependency: DependencyType { } // you need to adopt DependencyType protocol here.
// AppRouterGroup.swift
// A type that manages the pages you want to go with LinkNavigator.
import LinkNavigator
struct AppRouterGroup {
var routers: [RouteBuilder] {
[
HomeRouteBuilder(), // to be implemented in Step 3
Page1RouteBuilder(),
Page2RouteBuilder(),
Page3RouteBuilder(),
Page4RouteBuilder(),
]
}
}
// AppDelegate.swift
// A type that manages the navigator injected with external dependencies and pages.
import SwiftUI
import LinkNavigator
final class AppDelegate: NSObject {
var navigator: LinkNavigator {
LinkNavigator(dependency: AppDependency(), builders: AppRouterGroup().routers)
}
}
extension AppDelegate: UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
true
}
}
// AppMain.swift
// A type that sets the starting page of the Application.
import SwiftUI
import LinkNavigator
@main
struct AppMain: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
var navigator: LinkNavigator {
appDelegate.navigator
}
var body: some Scene {
WindowGroup {
navigator
.launch(paths: ["home"], items: [:]) // the argument of 'paths' becomes starting pages.
.onOpenURL { url in
// in case you need deep link navigation,
// deep links should be processed here.
}
}
}
}
Add a navigator
property inside the page struct type, so that it is injected when initialized.
Depending on the characteristics of the architecture, freely change the position of the navigator property and use it.
For example, you can put it in ViewModel
or Environment
.
struct HomePage: View {
let navigator: LinkNavigatorType
var body: some View {
...
}
}
Create a struct type adopting the RouteBuilder
protocol for every page.
RouteBuilder structs created in this way are collected and managed in the AppRouterGroup type.
import LinkNavigator
import SwiftUI
struct HomeRouteBuilder: RouteBuilder {
var matchPath: String { "home" }
var build: (LinkNavigatorType, [String: String], DependencyType) -> MatchingViewController? {
{ navigator, items, dependency in
return WrappingController(matchPath: matchPath) {
HomePage(navigator: navigator)
}
}
}
}
LinkNavigator supports Swift Package Manager.
File
menu at the top of Xcode -> Select Add Packages...
.Package.swift
.let package = Package(
name: "MyPackage",
products: [
.library(
name: "MyPackage",
targets: ["MyPackage"]),
],
dependencies: [
.package(url: "https://github.com/interactord/LinkNavigator.git", .upToNextMajor(from: "0.6.1"))
],
targets: [
.target(
name: "MyPackage",
dependencies: ["LinkNavigator"])
]
)
/// in AppMain.swift (MVI)
/// To use for route navigation, set the prefersLargeTitles parameter to true in the launch method.
navigator
.launch(paths: ["home"], items: [:], prefersLargeTitles: true)
/// in HomeView.swift (MVI)
/// To specify the display mode of the navigation bar title, use the navigationBarTitleDisplayMode (.line, .large, .automatic) in the SwiftUI screen of each screen.
ScrollView {
....
}
.navigationBarTitleDisplayMode(.large)
.navigationTitle("Home")
/// If you want to use it in fullSheet or customSheet,
/// Home.intent (MVI)
/// To enable large titles, set the prefersLargeTitles variable to true. To maintain the current settings, use .none.
navigator.fullSheet(paths: ["page1", "page2"], items: [:], isAnimated: true, prefersLargeTitles: true)
Q: I'm wondering how to apply IgnoringSafeArea to a specific part or the entire screen if I want to?
navigator
.launch(paths: ["home"], items: [:], prefersLargeTitles: true)
/// - Note:
/// If you are using the ignoresSafeArea property to ignore the safe area on an internal screen,
/// please add the corresponding code to the part where you first execute the LinkNavigator.
.ignoresSafeArea()
This library is released under the MIT license. See LICENSE for details.
link |
Stars: 177 |
Last commit: 3 days ago |
Full Changelog: 0.6.4
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics