Skip to content

Instantly share code, notes, and snippets.

@ChrisMarshallNY
Last active July 14, 2022 17:57
Show Gist options
  • Save ChrisMarshallNY/0a0ecab9395cad51af3aadf967beccfd to your computer and use it in GitHub Desktop.
Save ChrisMarshallNY/0a0ecab9395cad51af3aadf967beccfd to your computer and use it in GitHub Desktop.
A UIViewController Fade Animator
import UIKit
/* ###################################################################################################################################### */
// MARK: Fade Transition Animator
/* ###################################################################################################################################### */
/**
This allows us to do a fade between two screens.
It was inspired by [this Medium post](https://medium.com/@ludvigeriksson/custom-interactive-uinavigationcontroller-transition-animations-in-swift-4-a4b5e0cefb1e)
*/
open class RVS_FadeAnimator: NSObject, UIViewControllerAnimatedTransitioning {
/* ################################################################## */
/**
This is set to true, if the operation is a "push," and false, if it is a "pop."
*/
private var _presenting: Bool = false
/* ################################################################## */
/**
The animation period, in seconds.
*/
private var _animationPeriod: TimeInterval = 0.5
/* ################################################################## */
/**
This is the "public face" of the duration of our transition, in seconds.
- parameter using: The context (ignored).
- returns: The time interval for the transition, in seconds.
*/
public func transitionDuration(using: UIViewControllerContextTransitioning?) -> TimeInterval { _animationPeriod }
/* ################################################################## */
/**
This actually performs the fade animation.
- parameter using: The transition context, which we mine for "to" and "from" view controllers.
*/
public func animateTransition(using inContext: UIViewControllerContextTransitioning) {
guard let fromView = inContext.view(forKey: .from),
let toView = inContext.view(forKey: .to)
else { return }
let container = inContext.containerView
if _presenting {
container.addSubview(toView)
toView.alpha = 0.0
} else {
container.insertSubview(toView, belowSubview: fromView)
}
UIView.animate(withDuration: transitionDuration(using: inContext), animations: { [weak self] in
if self?._presenting ?? false {
toView.alpha = 1.0
} else {
fromView.alpha = 0.0
}
}, completion: { _ in
let success = !inContext.transitionWasCancelled
if !success {
toView.removeFromSuperview()
}
inContext.completeTransition(success)
})
}
/* ################################################################## */
/**
The initializer.
- parameter presenting: True, if the operation is a "push."
- parameter animationPeriodInSeconds: The animation period, in seconds. This is optional. If not provided, the period is half a second.
*/
public init(presenting inPresenting: Bool, animationPeriodInSeconds inAnimationPeriod: TimeInterval! = nil) {
_presenting = inPresenting
guard let animationPeriod = inAnimationPeriod else { return }
_animationPeriod = animationPeriod
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment