✨ LinkNavigator 는 SwiftUI 에서 화면을 자유롭게 이동할 수 있도록 도와주는 라이브러리입니다.
- URL path 형식의 표현 방법을 통해, 화면 이동에 대한 직관적인 syntax 를 제공합니다.
- 딥링크 처리 방식으로 어떤 화면이든 간편하게 이동할 수 있습니다.
- 화면 이동과 함께 매개변수를 주입할 수 있습니다.
- MVI 디자인 패턴, 혹은 pointfreeco 의 The Composable Architecture 와 같은 Uni-directional Architecture 에서 사용할 목적으로 디자인 되었지만, 그 외의 Architecture 에서도 사용하기 좋습니다.
-
하나 혹은 여러 개의 화면을 push 합니다.
navigator.next(paths: ["page1", "page2"], items: [:], isAnimated: true)
-
하나 혹은 여러 개의 화면을 pop 합니다.
navigator.remove(paths: ["pageToRemove"])
-
이전 화면으로 돌아가거나, modal 을 내립니다.
navigator.back(isAnimated: true)
-
원하는 화면으로 이동합니다. 그 화면이 이미 네비게이션 스택에 존재한다면, 원하는 화면까지 이동하면서 그 사이의 다른 화면들을 pop 합니다. 만약 네비게이션 스택에 없던 새로운 화면이라면, 새롭게 push 합니다.
navigator.backOrNext(path: "targetPage", items: [:], isAnimated: true)
-
현재의 네비게이션 스택을 교체합니다.
navigator.replace(paths: ["main", "depth1", "depth2"], items: [:], isAnimated: true)
-
원하는 화면을 sheet 또는 full screen cover modal 로 올립니다.
navigator.sheet(paths: ["sheetPage"], items: [:], isAnimated: true) navigator.fullSheet(paths: ["page1", "page2"], items: [:], isAnimated: true)
-
modal 을 내린 후 completion 클로저를 실행합니다.
navigator.close(isAnimated: true) { print("modal dismissed!") }
-
시스템 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)
-
복잡한 경로를 편집해서 사용할 수 있습니다.
// 현재 네비게이션 스택 == ["home", "depth1", "depth2", "depth3"] // 목표 스택 == ["home", "depth1", "newDepth"] var new = navigator.range(path: "depth1") + ["newDepth"] navigator.replace(paths: new, items: [:], isAnimated: true)
-
modal 뒤에 있는 화면을 조종할 수 있습니다.
navigator.rootNext(paths: ["targetPage"], items: [:], isAnimated: true) navigator.rootBackOrNext(path: "targetPage", items: [:], isAnimated: true)
-
아이폰, 아이패드 각각에 대한 modal presentation 스타일을 선택할 수 있습니다.
navigator.customSheet( paths: ["sheetPage"], items: [:], isAnimated: true, iPhonePresentationStyle: .fullScreen, iPadPresentationStyle: .pageSheet)
-
modal 뒤의 최상단에 있는 화면을 강제로 reload 합니다. onAppear(perform:) 수정자를 다시 호출해야 할 때 유용합니다.
navigator.rootReloadLast(items: [:], isAnimated: false)
LinkNavigator 는 2가지 예제를 제공합니다.
MVI
기반 예제TCA
기반 예제 - with 0.49.2 release
-
SwiftUI 프로젝트에 LinkNavigator 를 설치하기 위해서, 총 4개의 파일을 설정해야 합니다.
-
파일, 타입의 이름은 자유롭게 수정해도 됩니다. 다음 예시에서는 이해를 돕기 위해 단순한 이름을 사용했습니다.
-
AppDependency -> AppRouterGroup -> AppDelegate -> AppMain 순서로 설명합니다.
// AppDependency.swift // 외부 의존성을 관리하는 타입입니다. import LinkNavigator struct AppDependency: DependencyType { } // DependencyType 프로토콜을 채택해야 합니다.
// AppRouterGroup.swift // LinkNavigator 를 통해 이동하고 싶은 화면들을 관리하는 타입입니다. import LinkNavigator struct AppRouterGroup { var routers: [RouteBuilder] { [ HomeRouteBuilder(), // Step 3 에서 구현 Page1RouteBuilder(), Page2RouteBuilder(), Page3RouteBuilder(), Page4RouteBuilder(), ] } }
// AppDelegate.swift // 외부 의존성과 화면을 주입받은 navigator 를 관리하는 타입입니다. 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 // 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: [:]) // 'paths' 파라미터의 인자가 시작 페이지로 설정됩니다. .onOpenURL { url in // 딥링크 네비게이션이 필요한 경우, // URL 편집은 여기서 수행합니다. } } } }
-
화면에 해당하는 구조체 내부에
navigator
프로퍼티를 추가하여, 이니셜라이징 될 때 주입되도록 합니다. -
Architecture 특징에 따라, navigator 프로퍼티의 위치를 자유롭게 변경해서 사용하세요. 예를 들어,
ViewModel
또는Environment
에 넣어서 사용해도 좋습니다.struct HomePage: View { let navigator: LinkNavigatorType var body: some View { ... } }
-
모든 화면에 각각에 대해
RouteBuilder
프로토콜을 채택한 구조체를 만듭니다. -
이렇게 만든 RouteBuilder 구조체들은 AppRouterGroup 타입에서 모아두고 관리합니다.
import LinkNavigator import SwiftUI struct HomeRouteBuilder: RouteBuilder { var matchPath: String { "home" } var build: (LinkNavigatorType, [String: String], DependencyType) -> UIViewController? { { navigator, items, dependency in return WrappingController(matchingKey: matchPath) { HomePage(navigator: navigator) } } } }
LinkNavigator 는 Swift Package Manager 를 지원합니다.
- Xcode 상단의
File
메뉴 ->Add Packages...
를 선택합니다. - Package URL 입력창에 "https://github.com/interactord/LinkNavigator.git" 를 입력해서 설치합니다.
- 혹은
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.5.4"))
],
targets: [
.target(
name: "MyPackage",
dependencies: ["LinkNavigator"])
]
)
이 라이브러리는 MIT 라이선스를 따릅니다. 자세한 내용은 LICENSE 를 확인해주세요.