Latest 1.3.2
Homepage https://github.com/iKrisLiu/Navigator
License MIT
Platforms ios 10.0
Authors

Navigator

badge-version
badge-pms
badge-languages
badge-platforms

Navigator is a generic navigation framework for view controllers. It can decouple the dependency of different modules/components/view controllers.

Features

  • Data passing between view controllers bidirectional, inject data provider implementation for mocking data.
  • Navigation between view controllers with system default or custom transition animation
  • Support deep link and universal link
  • Goto any navigator

Architecture

SmartNavigator

SmartNavigator

Installation

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Navigator into your Xcode project using Carthage, specify it in your Cartfile:

github "iKrisLiu/Navigator" ~> 1.0

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. To integrate Navigator into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'SmartNavigator', '~> 1.0'

Swift Package Manager

Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. To integrate Navigator into your Xcode project, specify it in your Package.swift.

dependencies: [
    .package(url: "https://github.com/iKrisLiu/Navigator", from: "1.0.0")
]

Usage

Initialize Root View Controller

NavigatonControler
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Decoupling Way: Recommend to use this way among modules
    // View controller class name (The swift class name should be "ModuleName.ClassName")
    let main = DataModel(vcName: "ModuleName.ViewController", navName: "UINavigationController", mode: .reset)

    // Coupling Way: Recommend to use this way inside one module
    let main = DataModel(vcClass: ViewController.self, navClass: UINavigationController.self, mode: .reset)

    // If present view controller without passing any `UINavigationController`, use it as default one.
    Navigator.defaultNavigationControllerClass = UINavigationController.self

    Navigator.root.window = window
    Navigator.root.show(main)

    return true
}
SplitViewControler
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let master = DataModel(vcClass: MasterViewController.self, navClass: UINavigationController.self)
    let detail = DataModel(vcClass: DetailViewController.self, navClass: UINavigationController.self)
    let split = DataModel(vcClass: SplitViewController.self, children: [master, detail])

    Navigator.root.window = window
    Navigator.root.show(split)

    return true
}
TabBarControler
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let firstTab = DataModel(vcClass: TabItemViewController.self, navClass: UINavigationController.self)

    let master = DataModel(vcClass: MasterViewController.self, navClass: UINavigationController.self)
    let detail = DataModel(vcClass: DetailViewController.self, navClass: UINavigationController.self)
    let secondTab = DataModel(vcClass: SplitViewController.self, children: [master, detail])

    let tabs = DataModel(vcClass: UITabBarController.self, mode: .reset, children: [firstTab, secondTab])

    Navigator.root.window = window
    Navigator.root.show(tabs)

    return true
}

Show / Dismiss

Supported navigation mode: Push, Present, Overlay and Popover

class DetailViewController: UIViewController {
    @objc private func onTapShowViewControler() {
        // Decoupling Way
        let data = DataModel(vcName: "UIViewController"), mode: .push)

        // Coupling Way
        // If present a view contoller without passing any `UINavigationController`, it will use `Navigator.defaultNavigationControllerClass`.
        let data = DataModel(vcClass: UIViewController.self, mode: .present, title: "Hello", additionalData: "You can pass any type object")

        navigator?.show(data)
    }

    @objc private func onTapShowPopoverViewControler() {
        // Show from bottom
        let data = DataModel(vcClass: UIViewController.self, mode: .overlay, title: "Hello", additionalData: "You can pass any type object")
        data.sourceRect = CGRect(origin: .zero, size: .init(width: 0, height: 500))

        // Show in center
        let data = DataModel(vcClass: UIViewController.self, mode: .popover, title: "Hello", additionalData: "You can pass any type object")
        data.sourceRect = CGRect(origin: .zero, size: .init(width: 300, height: 500))

        navigator?.show(data)
    }

    @objc private func onTapDismissViewControler() {
        let data = "You can pass any type object/struct, e.g. string, tuple, dictionary and so on"

        navigator?.dismiss()            // 0: dimiss current view controller, 1: dismiss top two view controllers.
        navigator?.dismiss(level: -1)   // Dismiss to root view controller of current navigator
        navigator?.dismiss(data)        // Pass data to previous view controller when dismiss
    }
}

DeepLink

Use Safari or other approaches to test the deep link

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
    // Show top view controller base on current vc stack
    Navigator.current.open(url: url) { (_) -> DataModel in
        // Parse the deep link url to below data model for showing
        return DataModel(vcClass: TopViewController.self)
    }

    // Show a chain of view controllers from root vc
    Navigator.root.open(url: url) { (_) -> DataModel in
        // Parse the deep link url to below data models for showing
        let root = DataModel(vcClass: MainViewController.self, navClass: UINavigationController.self, mode: .reset)
        let middle = DataModel(vcClass: MiddleViewController.self)
        let top = DataModel(vcClass: TopViewController.self)

        return root --> middle --> top
    }

    return true
}

Transition Animation

Create custom transition class inherits the Transition class and override below two methods. Then pass transition class with custom transition class name in data model.

class CustomTransition: Transition {
    public override func animateNavigationTransition(from fromView: UIView?, to toView: UIView?) { }
    public override func animatePresentingTransition(from fromView: UIView?, to toView: UIView?) { }
}

class DetailViewController: UIViewController {
    @objc private func onTapShowViewControler() {
        let data = DataModel(vcClass: UIViewController.self, mode: .present)
        data.transitionStyle = .flipHorizontal

        let data = DataModel(vcClass: UIViewController.self, mode: .present)
        data.transitionName = "CustomTransition"

        navigator?.show(data)
    }
}

Data Receiving

class DetailViewController: UIViewController, NavigatorDataProtocol {
    private var data: Any?

    // Receive this callback when open by other view controller
    func onDataReceiveBeforeShow(_ data: DataModel, fromViewController: UIViewController?) {
        title = data.title
        data = data.additionalData
    }

    // Receive this callback when dismiss from next view controller
    func onDataReceiveAfterBack(_ data: Any?, fromViewController: UIViewController?) {
        self.data = data
    }
}

Latest podspec

{
    "name": "SmartNavigator",
    "version": "1.3.2",
    "license": "MIT",
    "summary": "Generic navigation framework for view controllers",
    "homepage": "https://github.com/iKrisLiu/Navigator",
    "authors": {
        "Kris Liu": "[email protected]"
    },
    "source": {
        "git": "https://github.com/iKrisLiu/Navigator.git",
        "tag": "1.3.2"
    },
    "platforms": {
        "ios": "10.0"
    },
    "swift_versions": [
        "4.2",
        "5.0"
    ],
    "module_name": "Navigator",
    "source_files": "Navigator/**/*.{h,m,swift}"
}

Pin It on Pinterest

Share This