Last active
February 12, 2019 05:43
-
-
Save NeilsUltimateLab/4b5b456ce0b1133be663ab067f3403c3 to your computer and use it in GitHub Desktop.
Custom UIViewController transition. Supports pop and modal transition.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
extension ModalPresentationAnimator { | |
enum Mode { | |
case present | |
case dismiss | |
} | |
enum AnimationStyle { | |
case modal | |
case pop | |
} | |
enum SizeMode { | |
case automatic | |
case manual(size: CGSize) | |
} | |
} | |
class ModalPresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning { | |
var duration: TimeInterval = 0.5 | |
var mode: Mode = .present | |
var animationStyle: AnimationStyle = .modal | |
var darkness: CGFloat = 0.5 | |
var sizeMode: SizeMode = .automatic | |
private lazy var backgroundView: UIView = { | |
let view = UIView(frame: .zero) | |
view.backgroundColor = UIColor.black.withAlphaComponent(darkness) | |
return view | |
}() | |
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { | |
return duration | |
} | |
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
let containerView = transitionContext.containerView | |
let fromView = transitionContext.view(forKey: .from) | |
let toView = transitionContext.view(forKey: .to) | |
switch mode { | |
case .present: | |
guard let toView = toView else { return } | |
containerView.addSubview(backgroundView) | |
backgroundView.frame = containerView.bounds | |
backgroundView.alpha = 0 | |
containerView.addSubview(toView) | |
let size: CGSize | |
switch sizeMode { | |
case .automatic: | |
size = toView.systemLayoutSizeFitting(CGSize(width: containerView.frame.width - 50, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.defaultLow) | |
case .manual(size: let mSize): | |
size = mSize | |
} | |
toView.frame.size = size | |
switch animationStyle { | |
case .modal: | |
toView.center = CGPoint(x: containerView.center.x, y: containerView.frame.height + toView.frame.height/2) | |
case .pop: | |
toView.center = containerView.center | |
toView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01) | |
toView.alpha = 0 | |
} | |
toView.layer.cornerRadius = 16 | |
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: UIView.AnimationOptions.curveEaseInOut, animations: { | |
toView.center = containerView.center | |
if self.animationStyle == .pop { | |
toView.transform = .identity | |
toView.alpha = 1 | |
} | |
self.backgroundView.alpha = 1 | |
}) { (success) in | |
transitionContext.completeTransition(success) | |
} | |
case .dismiss: | |
guard let fromView = fromView else { return } | |
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: { | |
switch self.animationStyle { | |
case .modal: | |
fromView.center = CGPoint(x: containerView.center.x, y: containerView.frame.height + fromView.frame.height/2) | |
case .pop: | |
fromView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01) | |
fromView.alpha = 0 | |
} | |
self.backgroundView.alpha = 0 | |
}) { (success) in | |
self.backgroundView.removeFromSuperview() | |
transitionContext.completeTransition(success) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment