Instantly share code, notes, and snippets.
Last active
January 18, 2021 08:12
-
Star
(4)
4
You must be signed in to star a gist -
Fork
(1)
1
You must be signed in to fork a gist
-
Save stuartjmoore/037dda91cc25daf66cd2d6578de41285 to your computer and use it in GitHub Desktop.
Re-create the Default `UINavigationController` Transition in iOS 10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NavigationParallaxTransition.swift | |
// NavigationTransition | |
// | |
// Created by Stuart Moore on 2/12/17. | |
// Copyright © 2017 Stuart J. Moore. All rights reserved. | |
// | |
import UIKit | |
private class NavigationParallaxTransitionTimingCurve: NSObject, UITimingCurveProvider { | |
override init() { | |
super.init() | |
} | |
required convenience init?(coder aDecoder: NSCoder) { | |
self.init() | |
} | |
public func copy(with zone: NSZone? = nil) -> Any { | |
return NavigationParallaxTransitionTimingCurve() | |
} | |
public func encode(with aCoder: NSCoder) { | |
return | |
} | |
var timingCurveType: UITimingCurveType { | |
return .composed | |
} | |
var cubicTimingParameters: UICubicTimingParameters? { | |
return UICubicTimingParameters(controlPoint1: CGPoint(x: 0.1878, y: 0.0023), controlPoint2: CGPoint(x: 0.5399, y: 0.9629)) | |
} | |
var springTimingParameters: UISpringTimingParameters? { | |
return UISpringTimingParameters(mass: 3, stiffness: 1000, damping: 500, initialVelocity: .zero) | |
} | |
} | |
final class NavigationParallaxTransition: NSObject, UIViewControllerAnimatedTransitioning { | |
let duration: TimeInterval = 0.35 | |
let operation: UINavigationControllerOperation | |
init(operation: UINavigationControllerOperation) { | |
self.operation = operation | |
} | |
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { | |
return duration | |
} | |
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
switch operation { | |
case .push: | |
animatePushTransition(using: transitionContext) | |
case .pop: | |
animatePopTransition(using: transitionContext) | |
case .none: | |
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
} | |
} | |
func animatePushTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
guard let toViewController = transitionContext.viewController(forKey: .to), | |
let fromViewController = transitionContext.viewController(forKey: .from) else { | |
return transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
} | |
let blackOverlayView = UIView(frame: fromViewController.view.frame) | |
blackOverlayView.backgroundColor = UIColor.black.withAlphaComponent(0.1) | |
blackOverlayView.alpha = 0 | |
transitionContext.containerView.addSubview(blackOverlayView) | |
toViewController.view.frame = transitionContext.finalFrame(for: toViewController) | |
toViewController.view.frame.origin.x = toViewController.view.frame.width | |
transitionContext.containerView.addSubview(toViewController.view) | |
let shadowView = UIImageView(image: #imageLiteral(resourceName: "shadow")) | |
shadowView.frame.size = CGSize(width: 6, height: toViewController.view.frame.height) | |
shadowView.frame.origin = CGPoint(x: toViewController.view.frame.minX - shadowView.frame.width, y: 0) | |
transitionContext.containerView.addSubview(shadowView) | |
let timing = NavigationParallaxTransitionTimingCurve() | |
let animation = UIViewPropertyAnimator(duration: duration, timingParameters: timing) | |
animation.addAnimations { | |
blackOverlayView.alpha = 1 | |
toViewController.view.frame.origin.x = 0 | |
shadowView.alpha = 0 | |
shadowView.frame.origin.x = -(shadowView.frame.width) | |
fromViewController.view.frame.origin.x = fromViewController.view.frame.width / -4 | |
} | |
animation.addCompletion { _ in | |
blackOverlayView.removeFromSuperview() | |
shadowView.removeFromSuperview() | |
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
} | |
animation.startAnimation() | |
} | |
func animatePopTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
guard let toViewController = transitionContext.viewController(forKey: .to), | |
let fromViewController = transitionContext.viewController(forKey: .from) else { | |
return transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
} | |
toViewController.view.frame = transitionContext.finalFrame(for: toViewController) | |
toViewController.view.frame.origin.x = toViewController.view.frame.width / -4 | |
transitionContext.containerView.insertSubview(toViewController.view, at: 0) | |
let blackOverlayView = UIView(frame: fromViewController.view.frame) | |
blackOverlayView.backgroundColor = UIColor.black.withAlphaComponent(0.1) | |
blackOverlayView.alpha = 1 | |
transitionContext.containerView.insertSubview(blackOverlayView, aboveSubview: toViewController.view) | |
let shadowView = UIImageView(image: #imageLiteral(resourceName: "shadow")) | |
shadowView.frame.size = CGSize(width: 6, height: toViewController.view.frame.height) | |
shadowView.frame.origin = CGPoint(x: -(shadowView.frame.width), y: 0) | |
transitionContext.containerView.addSubview(shadowView) | |
let timing = NavigationParallaxTransitionTimingCurve() | |
let animation = UIViewPropertyAnimator(duration: duration, timingParameters: timing) | |
animation.addAnimations { | |
blackOverlayView.alpha = 0 | |
toViewController.view.frame.origin.x = 0 | |
shadowView.alpha = 0 | |
shadowView.frame.origin.x = fromViewController.view.frame.width - shadowView.frame.width | |
fromViewController.view.frame.origin.x = fromViewController.view.frame.width | |
} | |
animation.addCompletion { _ in | |
blackOverlayView.removeFromSuperview() | |
shadowView.removeFromSuperview() | |
fromViewController.view.removeFromSuperview() | |
transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
} | |
animation.startAnimation() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment