Skip to content

Instantly share code, notes, and snippets.

@NeilsUltimateLab
Last active February 12, 2019 05:43
Show Gist options
  • Save NeilsUltimateLab/4b5b456ce0b1133be663ab067f3403c3 to your computer and use it in GitHub Desktop.
Save NeilsUltimateLab/4b5b456ce0b1133be663ab067f3403c3 to your computer and use it in GitHub Desktop.
Custom UIViewController transition. Supports pop and modal transition.
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