123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- //
- // Created by Tom Baranes on 24/04/16.
- // Copyright © 2016 IBAnimatable. All rights reserved.
- //
- import UIKit
- public class NatGeoAnimator: NSObject, AnimatedTransitioning {
- // MARK: - AnimatorProtocol
- public var transitionAnimationType: TransitionAnimationType
- public var transitionDuration: Duration = defaultTransitionDuration
- public var reverseAnimationType: TransitionAnimationType?
- public var interactiveGestureType: InteractiveGestureType?
- // MARK: - private
- fileprivate var fromDirection: TransitionAnimationType.Direction
- fileprivate let firstPartRatio: Double = 0.8
- // MARK: - Life cycle
- public init(from direction: TransitionAnimationType.Direction, duration: Duration) {
- transitionDuration = duration
- fromDirection = direction
- transitionAnimationType = .natGeo(to: direction)
- reverseAnimationType = .natGeo(to: direction.opposite)
- super.init()
- }
- }
- extension NatGeoAnimator: UIViewControllerAnimatedTransitioning {
- public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
- return retrieveTransitionDuration(transitionContext: transitionContext)
- }
- public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
- let (tempfromView, tempToView, tempContainerView) = retrieveViews(transitionContext: transitionContext)
- guard let fromView = tempfromView,
- let toView = tempToView,
- let containerView = tempContainerView else {
- transitionContext.completeTransition(true)
- return
- }
- let (_, tempToViewController, _) = retrieveViewControllers(transitionContext: transitionContext)
- if let toViewController = tempToViewController {
- toView.frame = transitionContext.finalFrame(for: toViewController)
- }
- containerView.addSubview(toView)
- containerView.addSubview(fromView)
- if fromDirection == .left {
- executeLeftAnimation(context: transitionContext, containerView: containerView, fromView: fromView, toView: toView)
- } else {
- executeRightAnimations(context: transitionContext, containerView: containerView, fromView: fromView, toView: toView)
- }
- }
- }
- // MARK: - Left
- private extension NatGeoAnimator {
- func executeLeftAnimation(context transitionContext: UIViewControllerContextTransitioning,
- containerView: UIView,
- fromView: UIView,
- toView: UIView) {
- fromView.isUserInteractionEnabled = false
- var fromLayer = fromView.layer
- var toLayer = toView.layer
- let oldFrame = fromLayer.frame
- let oldCenter = fromView.center
- let oldAnchorPoint = fromLayer.anchorPoint
- fromLayer.anchorPoint = CGPoint(x: 0.0, y: 0.5)
- fromLayer.frame = oldFrame
- sourceFirstTransform(&fromLayer)
- destinationFirstTransform(&toLayer)
- UIView.animateKeyframes(withDuration: transitionDuration, delay: 0.0, options: .calculationModeCubic, animations: {
- UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0) {
- self.destinationLastTransform(&toLayer)
- }
- UIView.addKeyframe(withRelativeStartTime: 1.0 - self.firstPartRatio, relativeDuration: self.firstPartRatio) {
- self.sourceLastTransform(&fromLayer)
- }
- }) { _ in
- if transitionContext.transitionWasCancelled {
- containerView.bringSubviewToFront(fromView)
- fromView.isUserInteractionEnabled = true
- }
- self.animationDidFinish(transitionContext, containerView: containerView, fromView: fromView, toView: toView)
- fromLayer.anchorPoint = oldAnchorPoint
- fromView.center = oldCenter
- }
- }
- }
- // MARK: - Right
- private extension NatGeoAnimator {
- func executeRightAnimations(context transitionContext: UIViewControllerContextTransitioning,
- containerView: UIView,
- fromView: UIView,
- toView: UIView) {
- toView.isUserInteractionEnabled = true
- var fromLayer = toView.layer
- var toLayer = fromView.layer
- let oldFrame = fromLayer.frame
- let oldCenter = toView.center
- let oldAnchorPoint = fromLayer.anchorPoint
- fromLayer.anchorPoint = CGPoint(x: 0.0, y: 0.5)
- fromLayer.frame = oldFrame
- sourceLastTransform(&fromLayer)
- destinationLastTransform(&toLayer)
- UIView.animateKeyframes(withDuration: transitionDuration, delay: 0.0, options: .calculationModeCubic, animations: {
- UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: self.firstPartRatio) {
- self.sourceFirstTransform(&fromLayer)
- }
- UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0) {
- self.destinationFirstTransform(&toLayer)
- }
- }) { _ in
- if transitionContext.transitionWasCancelled {
- containerView.bringSubviewToFront(fromView)
- toView.isUserInteractionEnabled = false
- }
- self.animationDidFinish(transitionContext, containerView: containerView, fromView: fromView, toView: toView)
- fromLayer.anchorPoint = oldAnchorPoint
- toView.center = oldCenter
- }
- }
- }
- // MARK: - Helpers
- private extension NatGeoAnimator {
- func sourceFirstTransform(_ layer: inout CALayer) {
- var transform = CATransform3DIdentity
- transform.m34 = 1.0 / -500
- transform = CATransform3DTranslate(transform, 0.0, 0.0, 0.0)
- layer.transform = transform
- }
- func sourceLastTransform(_ layer: inout CALayer) {
- var transform = CATransform3DIdentity
- transform.m34 = 1.0 / -500.0
- transform = CATransform3DRotate(transform, radianFromDegree(80), 0.0, 1.0, 0.0)
- transform = CATransform3DTranslate(transform, 0.0, 0.0, -30.0)
- transform = CATransform3DTranslate(transform, 170.0, 0.0, 0.0)
- layer.transform = transform
- }
- func destinationFirstTransform(_ layer: inout CALayer) {
- var transform = CATransform3DIdentity
- transform.m34 = 1.0 / -500.0
- transform = CATransform3DRotate(transform, radianFromDegree(5.0), 0.0, 0.0, 1.0)
- transform = CATransform3DTranslate(transform, 320.0, -40.0, 150.0)
- transform = CATransform3DRotate(transform, radianFromDegree(-45), 0.0, 1.0, 0.0)
- transform = CATransform3DRotate(transform, radianFromDegree(10), 1.0, 0.0, 0.0)
- layer.transform = transform
- }
- func destinationLastTransform(_ layer: inout CALayer) {
- var transform = CATransform3DIdentity
- transform.m34 = 1.0 / -500
- transform = CATransform3DRotate(transform, radianFromDegree(0), 0.0, 0.0, 1.0)
- transform = CATransform3DTranslate(transform, 0.0, 0.0, 0.0)
- transform = CATransform3DRotate(transform, radianFromDegree(0), 0.0, 1.0, 0.0)
- transform = CATransform3DRotate(transform, radianFromDegree(0), 1.0, 0.0, 0.0)
- layer.transform = transform
- }
- func radianFromDegree(_ degrees: Double) -> CGFloat {
- return CGFloat((degrees / 180) * .pi)
- }
- func animationDidFinish(_ transitionContext: UIViewControllerContextTransitioning, containerView: UIView, fromView: UIView, toView: UIView) {
- fromView.layer.transform = CATransform3DIdentity
- toView.layer.transform = CATransform3DIdentity
- containerView.layer.transform = CATransform3DIdentity
- transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
- }
- }
|