123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- //
- // PresentrAnimation.swift
- // Presentr
- //
- // Created by Daniel Lozano on 5/14/16.
- // Copyright © 2016 danielozano. All rights reserved.
- //
- import UIKit
- /// Simplified wrapper for the UIViewControllerContextTransitioning protocol.
- public struct PresentrTransitionContext {
- public let containerView: UIView
- public let initialFrame: CGRect
- public let finalFrame: CGRect
- public let isPresenting: Bool
- public let fromViewController: UIViewController?
- public let toViewController: UIViewController?
- public let fromView: UIView?
- public let toView: UIView?
- public let animatingViewController: UIViewController?
-
- public let animatingView: UIView?
-
- }
- /// Options for the UIView animation.
- public enum AnimationOptions {
- case normal(duration: TimeInterval)
- case spring(duration: TimeInterval, delay: TimeInterval, damping: CGFloat, velocity: CGFloat)
- }
- /// Class that handles animating the transition. Override this class if you want to create your own transition animation.
- open class PresentrAnimation: NSObject {
- public var options: AnimationOptions
- public init(options: AnimationOptions = .normal(duration: 0.4)) {
- self.options = options
- }
- /// For simple transitions, override this method to calculate an initial frame for the animation. For more complex animations override beforeAnimation & performAnimation. Only override this method OR beforeAnimation & performAnimation. This method won't even be called if you override beforeAnimation.
- ///
- /// - Parameters:
- /// - containerFrame: The container frame for the animation.
- /// - finalFrame: The final frame for the animation.
- /// - Returns: The initial frame.
- open func transform(containerFrame: CGRect, finalFrame: CGRect) -> CGRect {
- var initialFrame = finalFrame
- initialFrame.origin.y = containerFrame.height + initialFrame.height
- return initialFrame
- }
- /// Actions to be performed in preparation, before an animation.
- ///
- /// - Parameter transitionContext: The context with everything needed for the animiation.
- open func beforeAnimation(using transitionContext: PresentrTransitionContext) {
- let finalFrameForVC = transitionContext.finalFrame
- let initialFrameForVC = transform(containerFrame: transitionContext.containerView.frame, finalFrame: finalFrameForVC)
- let initialFrame = transitionContext.isPresenting ? initialFrameForVC : finalFrameForVC
- transitionContext.animatingView?.frame = initialFrame
- }
- /// Actions to be performed for the animation.
- ///
- /// - Parameter transitionContext: The context with everything needed for the animiation.
- open func performAnimation(using transitionContext: PresentrTransitionContext) {
- let finalFrameForVC = transitionContext.finalFrame
- let initialFrameForVC = transform(containerFrame: transitionContext.containerView.frame, finalFrame: finalFrameForVC)
- let finalFrame = transitionContext.isPresenting ? finalFrameForVC : initialFrameForVC
- transitionContext.animatingView?.frame = finalFrame
- }
- /// Actions to be performed after the animation.
- ///
- /// - Parameter transitionContext: The context with everything needed for the animiation.
- open func afterAnimation(using transitionContext: PresentrTransitionContext) {
- // Any cleanup to be done after the animation is over.
- }
- }
- // MARK: - UIViewControllerAnimatedTransitioning
- extension PresentrAnimation: UIViewControllerAnimatedTransitioning {
- public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
- switch options {
- case let .normal(duration):
- return duration
- case let .spring(duration, _, _, _):
- return duration
- }
- }
- public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
- let containerView = transitionContext.containerView
-
- let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
- let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
- let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)
- let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)
- let isPresenting: Bool = (toViewController?.presentingViewController == fromViewController)
- let animatingVC = isPresenting ? toViewController : fromViewController
- let animatingView = isPresenting ? toView : fromView
- let initialFrame = transitionContext.initialFrame(for: animatingVC!)
- let finalFrame = transitionContext.finalFrame(for: animatingVC!)
- let presentrContext = PresentrTransitionContext(containerView: containerView,
- initialFrame: initialFrame,
- finalFrame: finalFrame,
- isPresenting: isPresenting,
- fromViewController: fromViewController,
- toViewController: toViewController,
- fromView: fromView,
- toView: toView,
- animatingViewController: animatingVC,
- animatingView: animatingView)
- if isPresenting {
- containerView.addSubview(toView!)
- }
- switch options {
- case let .normal(duration):
- animate(presentrContext: presentrContext,
- transitionContext: transitionContext,
- duration: duration)
- case let .spring(duration, delay, damping, velocity):
- animateWithSpring(presentrContext: presentrContext,
- transitionContext: transitionContext,
- duration: duration,
- delay: delay,
- damping: damping,
- velocity: velocity)
- }
- }
- private func animate(presentrContext: PresentrTransitionContext, transitionContext: UIViewControllerContextTransitioning, duration: TimeInterval) {
- beforeAnimation(using: presentrContext)
- UIView.animate(withDuration: duration, animations: {
- self.performAnimation(using: presentrContext)
- }) { (completed) in
- self.afterAnimation(using: presentrContext)
- transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
- }
- }
- private func animateWithSpring(presentrContext: PresentrTransitionContext, transitionContext: UIViewControllerContextTransitioning, duration: TimeInterval, delay: TimeInterval, damping: CGFloat, velocity: CGFloat) {
- beforeAnimation(using: presentrContext)
- UIView.animate(withDuration: duration,
- delay: delay,
- usingSpringWithDamping: damping,
- initialSpringVelocity: velocity,
- options: [],
- animations: {
- self.performAnimation(using: presentrContext)
- }) { (completed) in
- self.afterAnimation(using: presentrContext)
- transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
- }
- }
- }
|