TurnAnimator.swift 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. //
  2. // Created by Tom Baranes on 01/05/16.
  3. // Copyright © 2016 IBAnimatable. All rights reserved.
  4. //
  5. import UIKit
  6. public class TurnAnimator: 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? = .pan(from: .horizontal)
  12. // MARK: - Private params
  13. fileprivate var fromDirection: TransitionAnimationType.Direction
  14. // MARK: - Private fold transition
  15. fileprivate var transform: CATransform3D = CATransform3DIdentity
  16. fileprivate var reverse: Bool = false
  17. // MARK: - Life cycle
  18. public init(from direction: TransitionAnimationType.Direction, duration: Duration) {
  19. fromDirection = direction
  20. transitionDuration = duration
  21. transitionAnimationType = .turn(from: direction)
  22. reverseAnimationType = .turn(from: direction.opposite)
  23. interactiveGestureType = .pan(from: direction.opposingGesture)
  24. reverse = direction == .right || direction == .bottom
  25. super.init()
  26. }
  27. }
  28. extension TurnAnimator: UIViewControllerAnimatedTransitioning {
  29. public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
  30. return retrieveTransitionDuration(transitionContext: transitionContext)
  31. }
  32. public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
  33. let (tempfromView, tempToView, tempContainerView) = retrieveViews(transitionContext: transitionContext)
  34. guard let fromView = tempfromView, let toView = tempToView, let containerView = tempContainerView else {
  35. transitionContext.completeTransition(true)
  36. return
  37. }
  38. containerView.addSubview(toView)
  39. transform.m34 = -0.002
  40. containerView.layer.sublayerTransform = transform
  41. toView.frame = fromView.frame
  42. animateTurnTransition(fromView: fromView, toView: toView) {
  43. transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
  44. }
  45. }
  46. private func animateTurnTransition(fromView: UIView, toView: UIView, completion: @escaping AnimatableCompletion) {
  47. let factor = reverse ? 1.0 : -1.0
  48. toView.layer.transform = rotate(angle: factor * -.pi / 2)
  49. UIView.animateKeyframes(withDuration: transitionDuration, delay: 0.0, options: .layoutSubviews, animations: {
  50. UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5) {
  51. fromView.layer.transform = self.rotate(angle: factor * .pi / 2)
  52. }
  53. UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
  54. toView.layer.transform = self.rotate(angle: 0.0)
  55. }
  56. }) { _ in
  57. completion()
  58. }
  59. }
  60. }
  61. // MARK: - Helpers
  62. private extension TurnAnimator {
  63. func rotate(angle: Double) -> CATransform3D {
  64. if fromDirection == .left || fromDirection == .right {
  65. return CATransform3DMakeRotation(CGFloat(angle), 0.0, 1.0, 0.0)
  66. } else {
  67. return CATransform3DMakeRotation(CGFloat(angle), 1.0, 0.0, 0.0)
  68. }
  69. }
  70. }