123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- import UIKit
- class ZoomDismissalInteractionController: NSObject {
-
- var transitionContext: UIViewControllerContextTransitioning?
- var animator: UIViewControllerAnimatedTransitioning?
-
- var fromReferenceImageViewFrame: CGRect?
- var toReferenceImageViewFrame: CGRect?
-
- func didPanWith(gestureRecognizer: UIPanGestureRecognizer) {
-
- guard let transitionContext = self.transitionContext,
- let animator = self.animator as? ZoomAnimator,
- let transitionImageView = animator.transitionImageView,
- let fromVC = transitionContext.viewController(forKey: .from),
- let toVC = transitionContext.viewController(forKey: .to),
- let fromReferenceImageView = animator.fromDelegate?.referenceImageView(for: animator),
- let toReferenceImageView = animator.toDelegate?.referenceImageView(for: animator),
- let fromReferenceImageViewFrame = self.fromReferenceImageViewFrame,
- let toReferenceImageViewFrame = self.toReferenceImageViewFrame else {
- return
- }
-
-
- fromReferenceImageView.isHidden = true
-
- let anchorPoint = CGPoint(x: fromReferenceImageViewFrame.midX, y: fromReferenceImageViewFrame.midY)
- let translatedPoint = gestureRecognizer.translation(in: fromReferenceImageView)
- let verticalDelta : CGFloat = translatedPoint.y < 0 ? 0 : translatedPoint.y
- let backgroundAlpha = backgroundAlphaFor(view: fromVC.view, withPanningVerticalDelta: verticalDelta)
- let scale = scaleFor(view: fromVC.view, withPanningVerticalDelta: verticalDelta)
-
- fromVC.view.alpha = backgroundAlpha
-
- transitionImageView.transform = CGAffineTransform(scaleX: scale, y: scale)
- let newCenter = CGPoint(x: anchorPoint.x + translatedPoint.x, y: anchorPoint.y + translatedPoint.y - transitionImageView.frame.height * (1 - scale) / 2.0)
- transitionImageView.center = newCenter
-
- toReferenceImageView.isHidden = true
-
- transitionContext.updateInteractiveTransition(1 - scale)
-
- toVC.tabBarController?.tabBar.alpha = 1 - backgroundAlpha
-
- if gestureRecognizer.state == .ended {
-
- let velocity = gestureRecognizer.velocity(in: fromVC.view)
- if velocity.y < 0 || newCenter.y < anchorPoint.y {
-
- //cancel
- UIView.animate(
- withDuration: 0.5,
- delay: 0,
- usingSpringWithDamping: 0.9,
- initialSpringVelocity: 0,
- options: [],
- animations: {
- transitionImageView.frame = fromReferenceImageViewFrame
- fromVC.view.alpha = 1.0
- toVC.tabBarController?.tabBar.alpha = 0
- },
- completion: { completed in
-
- toReferenceImageView.isHidden = false
- fromReferenceImageView.isHidden = false
- transitionImageView.removeFromSuperview()
- animator.transitionImageView = nil
- transitionContext.cancelInteractiveTransition()
- transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
- animator.toDelegate?.transitionDidEndWith(zoomAnimator: animator)
- animator.fromDelegate?.transitionDidEndWith(zoomAnimator: animator)
- self.transitionContext = nil
- })
- return
- }
-
- //start animation
- let finalTransitionSize = toReferenceImageViewFrame
-
- UIView.animate(withDuration: 0.25,
- delay: 0,
- options: [],
- animations: {
- fromVC.view.alpha = 0
- transitionImageView.frame = finalTransitionSize
- toVC.tabBarController?.tabBar.alpha = 1
-
- }, completion: { completed in
-
- transitionImageView.removeFromSuperview()
- toReferenceImageView.isHidden = false
- fromReferenceImageView.isHidden = false
-
- self.transitionContext?.finishInteractiveTransition()
- transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
- animator.toDelegate?.transitionDidEndWith(zoomAnimator: animator)
- animator.fromDelegate?.transitionDidEndWith(zoomAnimator: animator)
- self.transitionContext = nil
- })
- }
- }
-
- func backgroundAlphaFor(view: UIView, withPanningVerticalDelta verticalDelta: CGFloat) -> CGFloat {
- let startingAlpha:CGFloat = 1.0
- let finalAlpha: CGFloat = 0.0
- let totalAvailableAlpha = startingAlpha - finalAlpha
-
- let maximumDelta = view.bounds.height / 4.0
- let deltaAsPercentageOfMaximun = min(abs(verticalDelta) / maximumDelta, 1.0)
-
- return startingAlpha - (deltaAsPercentageOfMaximun * totalAvailableAlpha)
- }
-
- func scaleFor(view: UIView, withPanningVerticalDelta verticalDelta: CGFloat) -> CGFloat {
- let startingScale:CGFloat = 1.0
- let finalScale: CGFloat = 0.5
- let totalAvailableScale = startingScale - finalScale
-
- let maximumDelta = view.bounds.height / 2.0
- let deltaAsPercentageOfMaximun = min(abs(verticalDelta) / maximumDelta, 1.0)
-
- return startingScale - (deltaAsPercentageOfMaximun * totalAvailableScale)
- }
- }
- extension ZoomDismissalInteractionController: UIViewControllerInteractiveTransitioning {
- func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
- self.transitionContext = transitionContext
-
- let containerView = transitionContext.containerView
-
- guard let animator = self.animator as? ZoomAnimator,
- let fromVC = transitionContext.viewController(forKey: .from),
- let toVC = transitionContext.viewController(forKey: .to),
- let fromReferenceImageViewFrame = animator.fromDelegate?.referenceImageViewFrameInTransitioningView(for: animator),
- let toReferenceImageViewFrame = animator.toDelegate?.referenceImageViewFrameInTransitioningView(for: animator),
- let fromReferenceImageView = animator.fromDelegate?.referenceImageView(for: animator)
- else {
- return
- }
-
- animator.fromDelegate?.transitionWillStartWith(zoomAnimator: animator)
- animator.toDelegate?.transitionWillStartWith(zoomAnimator: animator)
-
- self.fromReferenceImageViewFrame = fromReferenceImageViewFrame
- self.toReferenceImageViewFrame = toReferenceImageViewFrame
-
- let referenceImage = fromReferenceImageView.image!
-
- containerView.insertSubview(toVC.view, belowSubview: fromVC.view)
- if animator.transitionImageView == nil {
- let transitionImageView = UIImageView(image: referenceImage)
- transitionImageView.contentMode = .scaleAspectFill
- transitionImageView.clipsToBounds = true
- transitionImageView.frame = fromReferenceImageViewFrame
- animator.transitionImageView = transitionImageView
- containerView.addSubview(transitionImageView)
- }
- }
- }
|