Files
navigation-stack/Source/NavigationStack.swift
2018-09-17 10:20:21 +03:00

172 lines
6.8 KiB
Swift

//
// NavigationStack.swift
// NavigationStackDemo
//
// Copyright (c) 26/02/16 Ramotion Inc. (http://ramotion.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
/// UINavigationcontroller with animation show lists of UIViewControllers
open class NavigationStack: UINavigationController {
var overlay: Float = 0.8
var scaleRatio: Float = 14.0
var scaleValue: Float = 0.99
/// A floating-point value that determines the rate of deceleration after the user lifts their finger.
@IBInspectable open var decelerationRate: CGFloat = UIScrollView.DecelerationRate.normal.rawValue
/// The color to use for the background of the lists of UIViewcontrollers.
@IBInspectable open var bgColor: UIColor = .black
/// The background UIView of the lists of UIViewcontrollers.
open var bgView: UIView?
fileprivate var screens = [UIImage]()
/// The delegate of the navigation controller object. Use this instead delegate.
open weak var stackDelegate: UINavigationControllerDelegate?
/**
The initialized navigation controller object or nil if there was a problem initializing the object.
- parameter aDecoder: aDecoder
- returns: The initialized navigation controller object or nil if there was a problem initializing the object.
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
delegate = self
}
/**
Initializes and returns a newly created navigation controller.
- parameter rootViewController: The view controller that resides at the bottom of the navigation stack.
- returns: The initialized navigation controller object or nil if there was a problem initializing the object.
*/
public override init(rootViewController: UIViewController) {
super.init(rootViewController: rootViewController)
delegate = self
}
/**
Necessary to prevent a crash
*/
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
}
// MARK: pulbic methods
extension NavigationStack {
/**
Show list of ViewControllers.
*/
public func showControllers() {
if screens.count == 0 {
return
}
var allScreens = screens
allScreens.append(view.takeScreenshot())
let collectioView = CollectionStackViewController(images: allScreens,
delegate: self,
overlay: overlay,
scaleRatio: scaleRatio,
scaleValue: scaleValue,
bgColor: bgColor,
bgView: bgView,
decelerationRate: decelerationRate)
present(collectioView, animated: false, completion: nil)
}
}
// MARK: UINavigationControllerDelegate
extension NavigationStack: UINavigationControllerDelegate {
public func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
stackDelegate?.navigationController?(navigationController, willShow: viewController, animated: animated)
if navigationController.viewControllers.count > screens.count + 1 {
screens.append(view.takeScreenshot())
} else
if navigationController.viewControllers.count == screens.count && screens.count > 0 {
screens.removeLast()
}
}
public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
stackDelegate?.navigationController?(navigationController, didShow: viewController, animated: animated)
}
// ???
// public func navigationControllerSupportedInterfaceOrientations(navigationController: UINavigationController) -> UIInterfaceOrientationMask {
// return stackDelegate?.navigationControllerSupportedInterfaceOrientations?(navigationController)
// }
// ???
// optional public func navigationControllerPreferredInterfaceOrientationForPresentation(navigationController: UINavigationController) -> UIInterfaceOrientation
//
public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return stackDelegate?.navigationController?(navigationController, interactionControllerFor: animationController)
}
public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return stackDelegate?.navigationController?(navigationController, animationControllerFor: operation, from: fromVC, to: toVC)
}
}
extension NavigationStack: CollectionStackViewControllerDelegate {
func controllerDidSelected(index: Int) {
let newViewControllers = Array(viewControllers[0 ... index])
setViewControllers(newViewControllers, animated: false)
screens.removeSubrange(index ..< screens.count)
}
}
// MARK: UIView
extension UIView {
func takeScreenshot() -> UIImage {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale)
layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}