• Stars
    star
    232
  • Rank 172,847 (Top 4 %)
  • Language
    Swift
  • License
    Other
  • Created over 2 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐ŸŒŠ Easy & Powerful navigation library in SwiftUI

Swift Version License

- Concept

โœจ LinkNavigator is a library that helps you easily navigate between pages in SwiftUI.

  • LinkNavigator provides an intuitive syntax for navigating pages via URL path-like expressions.
  • You can easily go to any page with the deep-link processing style.
  • You can inject parameters with page transition.
  • LinkNavigator is designed for use in Uni-directional Architecture such as MVI design pattern or The Composable Architecture from pointfreeco, but it can be used in other architectures as well.

- Translations

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!


- Basic Usage

  • 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)

- Advanced Usage

  • 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)

- Example

LinkNavigator provides 2 Example Apps.


- Getting Started

Step 1

  • 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.
            }
        }
      }
    }

Step 2

  • 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 {
        ...
      }
    }

Step 3

  • 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)
          }
        }
      }
    }

- Installation

LinkNavigator supports Swift Package Manager.

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"])
  ]
)

- Extra

  • Q: How can I use large titles in SwiftUI?
  /// 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?

    1. Add the following code to the screen where LinkNavigator is first started (example: AppMain.swift).
    2. Then, add the following example code. (Refer to the AppMain.swift example.)
 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()

- License

This library is released under the MIT license. See LICENSE for details.

More Repositories

1

Boost

ํ† ์ดํ”„๋กœ์ ํŠธ
Swift
10
star
2

favorite

Github api๋ฅผ ์ด์šฉํ•œ ์˜ˆ์ œ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค
Swift
7
star
3

RemakeStore

An experimental remake of the iOS 12 App Store app
Swift
6
star
4

Enterprise-Architecture

ํ”Œ๋ฆฌํ† ์— ์ ์šฉ๋œ ์•„ํ‚คํ…Œ์ฒ˜๋ฅผ ๊ฐ ํŒŒํŠธ๋ณ„๋กœ ๋‚˜๋ˆˆ ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค.
Swift
6
star
5

SCTypeKit

Currying style of construct attributed string and font
Swift
5
star
6

Modoo

ํ•ด๋‹น ํ”„๋กœ์ ํŠธ๋Š” ์ธ์Šคํƒ€๊ทธ๋žจ์˜ ํด๋ก  ์•ฑ๋‹ˆ๋‹ค.
Swift
4
star
7

CameraScan

Swift
3
star
8

CloneAppstore

Swift
2
star
9

NoNibComponent

This library is used to create UIComponent programmatically without using xib or storyboard
Swift
2
star
10

URLEncodedForm

Parse and serialize url-encoded form data with Codable support.
Swift
2
star
11

RemakeAppStore

[developing] Remake iOS App Store
Swift
2
star
12

SCDataStructure

SCDataStructure๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์Šค์œ„ํ”„ํŠธ ๋ฒ„์ „์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค.
Swift
2
star
13

groov

Swift
2
star
14

SCUIBuildKit

SCBuildKit is make UIView
Swift
2
star
15

SwipeSlideMenu

Swift
2
star
16

KindleShelf

Swift
2
star
17

grab

Swift6.0
Swift
2
star
18

AStore

An experimental clone of the iOS 12 App Store app
Swift
2
star
19

Circle

ํ•™์Šต์šฉ ๊ณผ์ œ
Swift
1
star
20

SCLayoutKit

SCLayoutKit is auto layout helper class
Swift
1
star
21

SCServiceKit

Protocol base Service Kit
Swift
1
star