CardsAnimator.swift 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. //
  2. // Created by Tom Baranes on 01/05/16.
  3. // Copyright © 2016 IBAnimatable. All rights reserved.
  4. //
  5. import UIKit
  6. public class CardsAnimator: NSObject, AnimatedTransitioning {
  7. // MARK: - AnimatorProtocol
  8. public var transitionAnimationType: TransitionAnimationType
  9. public var transitionDuration: Duration = defaultTransitionDuration
  10. public var reverseAnimationType: TransitionAnimationType?
  11. public var interactiveGestureType: InteractiveGestureType?
  12. // MARK: - private
  13. fileprivate var fromDirection: TransitionAnimationType.Direction
  14. public init(from direction: TransitionAnimationType.Direction, duration: Duration) {
  15. transitionDuration = duration
  16. fromDirection = direction
  17. transitionAnimationType = .cards(direction: direction)
  18. reverseAnimationType = .cards(direction: direction.opposite)
  19. super.init()
  20. }
  21. }
  22. extension CardsAnimator: UIViewControllerAnimatedTransitioning {
  23. public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
  24. return retrieveTransitionDuration(transitionContext: transitionContext)
  25. }
  26. public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
  27. let (tempfromView, tempToView, tempContainerView) = retrieveViews(transitionContext: transitionContext)
  28. guard let fromView = tempfromView, let toView = tempToView, let containerView = tempContainerView else {
  29. transitionContext.completeTransition(true)
  30. return
  31. }
  32. if fromDirection == .forward {
  33. executeForwardAnimation(transitionContext: transitionContext, containerView: containerView, fromView: fromView, toView: toView)
  34. } else {
  35. executeBackwardAnimation(transitionContext: transitionContext, containerView: containerView, fromView: fromView, toView: toView)
  36. }
  37. }
  38. }
  39. // MARK: - Forward
  40. private extension CardsAnimator {
  41. func executeBackwardAnimation(transitionContext: UIViewControllerContextTransitioning, containerView: UIView, fromView: UIView, toView: UIView) {
  42. let frame = fromView.frame
  43. var offScreenFrame = frame
  44. offScreenFrame.origin.y = offScreenFrame.height
  45. toView.frame = offScreenFrame
  46. containerView.insertSubview(toView, aboveSubview: fromView)
  47. let t1 = firstTransform()
  48. let t2 = secondTransformWithView(view: fromView)
  49. UIView.animateKeyframes(withDuration: transitionDuration, delay: 0.0, options: .calculationModeCubic, animations: {
  50. UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.4) {
  51. fromView.layer.transform = t1
  52. fromView.alpha = 0.6
  53. }
  54. UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.4) {
  55. fromView.layer.transform = t2
  56. }
  57. UIView.addKeyframe(withRelativeStartTime: 0.6, relativeDuration: 0.2) {
  58. toView.frame = toView.frame.offsetBy(dx: 0.0, dy: -30.0)
  59. }
  60. UIView.addKeyframe(withRelativeStartTime: 0.8, relativeDuration: 0.2) {
  61. toView.frame = frame
  62. }
  63. }) { _ in
  64. transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
  65. }
  66. }
  67. }
  68. // MARK: - Reverse
  69. private extension CardsAnimator {
  70. func executeForwardAnimation(transitionContext: UIViewControllerContextTransitioning, containerView: UIView, fromView: UIView, toView: UIView) {
  71. let frame = fromView.frame
  72. toView.frame = frame
  73. let scale = CATransform3DIdentity
  74. toView.layer.transform = CATransform3DScale(scale, 0.6, 0.6, 1)
  75. toView.alpha = 0.6
  76. containerView.insertSubview(toView, belowSubview: fromView)
  77. var frameOffScreen = frame
  78. frameOffScreen.origin.y = frame.height
  79. let t1 = firstTransform()
  80. UIView.animateKeyframes(withDuration: transitionDuration, delay: 0.0, options: .calculationModeCubic, animations: {
  81. UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5) {
  82. fromView.frame = frameOffScreen
  83. }
  84. UIView.addKeyframe(withRelativeStartTime: 0.35, relativeDuration: 0.35) {
  85. toView.layer.transform = t1
  86. toView.alpha = 1.0
  87. }
  88. UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {
  89. toView.layer.transform = CATransform3DIdentity
  90. }
  91. }) { _ in
  92. if transitionContext.transitionWasCancelled {
  93. toView.layer.transform = CATransform3DIdentity
  94. toView.alpha = 1.0
  95. }
  96. transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
  97. }
  98. }
  99. }
  100. // MARK: - Helper
  101. private extension CardsAnimator {
  102. func firstTransform() -> CATransform3D {
  103. var t1 = CATransform3DIdentity
  104. t1.m34 = 1.0 / -900
  105. t1 = CATransform3DScale(t1, 0.95, 0.95, 1)
  106. t1 = CATransform3DRotate(t1, 15.0 * .pi / 180.0, 1, 0, 0)
  107. return t1
  108. }
  109. func secondTransformWithView(view: UIView) -> CATransform3D {
  110. var t2 = CATransform3DIdentity
  111. t2.m34 = firstTransform().m34
  112. t2 = CATransform3DTranslate(t2, 0, view.frame.size.height * -0.08, 0)
  113. t2 = CATransform3DScale(t2, 0.8, 0.8, 1)
  114. return t2
  115. }
  116. }