DropDownAnimator.swift 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. //
  2. // Created by Tom Baranes on 13/08/16.
  3. // Copyright © 2016 IBAnimatable. All rights reserved.
  4. //
  5. import UIKit
  6. public class DropDownAnimator: NSObject, AnimatedPresenting {
  7. // MARK: - AnimatedPresenting
  8. public var transitionDuration: Duration = defaultTransitionDuration
  9. fileprivate var timingFunctions: [TimingFunctionType] = [.easeOut, .linear, .easeOut]
  10. fileprivate var completion: AnimatableCompletion?
  11. // MARK: - Life cycle
  12. public init(duration: Duration) {
  13. transitionDuration = duration
  14. super.init()
  15. }
  16. }
  17. // MARK: - Animator
  18. extension DropDownAnimator: UIViewControllerAnimatedTransitioning {
  19. public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
  20. return retrieveTransitionDuration(transitionContext: transitionContext)
  21. }
  22. public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
  23. let (fromView, toView, tempContainerView) = retrieveViews(transitionContext: transitionContext)
  24. let isPresenting = self.isPresenting(transitionContext: transitionContext)
  25. guard let containerView = tempContainerView, let animatingView = isPresenting ? toView : fromView else {
  26. transitionContext.completeTransition(true)
  27. return
  28. }
  29. if isPresenting {
  30. containerView.addSubview(animatingView)
  31. }
  32. animateDropDown(animatingView: animatingView, isPresenting: isPresenting) {
  33. if !isPresenting {
  34. fromView?.removeFromSuperview()
  35. }
  36. transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
  37. }
  38. }
  39. }
  40. // MARK: - Animation
  41. private extension DropDownAnimator {
  42. func animateDropDown(animatingView: UIView, isPresenting: Bool, completion: @escaping AnimatableCompletion) {
  43. if isPresenting {
  44. animatePresengingDropDown(animatingView: animatingView, completion: completion)
  45. } else {
  46. animateDismissingDropDown(animatingView: animatingView, completion: completion)
  47. }
  48. }
  49. func animatePresengingDropDown(animatingView: UIView, completion: @escaping AnimatableCompletion) {
  50. let y = animatingView.center.y
  51. let animation = CAKeyframeAnimation(keyPath: .positionY)
  52. animation.values = [y - UIScreen.main.bounds.height, y + 20, y - 10, y]
  53. animation.keyTimes = [0, 0.5, 0.75, 1]
  54. animation.timingFunctionsType = timingFunctions
  55. animation.duration = transitionDuration
  56. animation.delegate = self
  57. self.completion = completion
  58. animatingView.layer.add(animation, forKey: "dropdown")
  59. }
  60. func animateDismissingDropDown(animatingView: UIView, completion: @escaping AnimatableCompletion) {
  61. var point = animatingView.center
  62. let angle = CGFloat(arc4random_uniform(100)) - 50
  63. point.y += UIScreen.main.bounds.height
  64. UIView.animate(withDuration: transitionDuration, animations: {
  65. animatingView.center = point
  66. animatingView.transform = CGAffineTransform(rotationAngle: angle / 100)
  67. }, completion: { _ in
  68. completion()
  69. })
  70. }
  71. }
  72. // MARK: - CAAnimationDelegate
  73. extension DropDownAnimator: CAAnimationDelegate {
  74. public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
  75. if let completion = completion {
  76. completion()
  77. self.completion = nil
  78. }
  79. }
  80. }