diff --git a/examples/ContextualTransitionExample.swift b/examples/ContextualTransitionExample.swift index db4ba3e..f4a05dc 100644 --- a/examples/ContextualTransitionExample.swift +++ b/examples/ContextualTransitionExample.swift @@ -165,7 +165,7 @@ class PhotoAlbumViewController: UIViewController, UICollectionViewDataSource, UI super.init(nibName: nil, bundle: nil) - transitionController.transitionType = PushBackTransition.self + transitionController.transition = PushBackTransition() } required init?(coder aDecoder: NSCoder) { @@ -258,8 +258,6 @@ class PhotoAlbumViewController: UIViewController, UICollectionViewDataSource, UI private class PushBackTransition: Transition { - required init() {} - func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] { let foreVC = ctx.fore as! PhotoAlbumViewController let foreImageView = (foreVC.collectionView.cellForItem(at: foreVC.indexPathForCurrentPhoto()) as! PhotoCollectionViewCell).imageView diff --git a/examples/FabTransitionExample.swift b/examples/FabTransitionExample.swift index fd6189c..03660c8 100644 --- a/examples/FabTransitionExample.swift +++ b/examples/FabTransitionExample.swift @@ -41,7 +41,7 @@ class FabTransitionExampleViewController: ExampleViewController, TransitionConte func didTap() { let vc = ModalViewController() - vc.transitionController.transitionType = CircularRevealTransition.self + vc.transitionController.transition = CircularRevealTransition() present(vc, animated: true) } @@ -76,18 +76,17 @@ private class ModalViewController: UIViewController { let floodFillOvershootRatio: CGFloat = 1.2 -private class CircularRevealTransition: Transition { +private class CircularRevealTransition: TransitionWithTermination { // TODO: Support for transient views. var floodFillView: UIView! var foreViewLayer: CALayer! - deinit { + + func didEndTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) { floodFillView.removeFromSuperview() foreViewLayer.mask = nil } - required init() {} - func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] { foreViewLayer = ctx.fore.view.layer diff --git a/examples/InteractivePushBackTransitionExample.swift b/examples/InteractivePushBackTransitionExample.swift index bb9e718..a47e072 100644 --- a/examples/InteractivePushBackTransitionExample.swift +++ b/examples/InteractivePushBackTransitionExample.swift @@ -41,7 +41,7 @@ private class ModalViewController: UIViewController, UIGestureRecognizerDelegate override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - transitionController.transitionType = PushBackTransition.self + transitionController.transition = PushBackTransition() } required init?(coder aDecoder: NSCoder) { @@ -72,8 +72,6 @@ private class ModalViewController: UIViewController, UIGestureRecognizerDelegate private class PushBackTransition: Transition { - required init() {} - func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] { let draggable = Draggable(withFirstGestureIn: ctx.gestureRecognizers) diff --git a/examples/ModalDialogExample.swift b/examples/ModalDialogExample.swift index 9756f04..a027bb3 100644 --- a/examples/ModalDialogExample.swift +++ b/examples/ModalDialogExample.swift @@ -45,7 +45,7 @@ class ModalDialogViewController: UIViewController { override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - transitionController.transitionType = ModalDialogTransition.self + transitionController.transition = ModalDialogTransition() preferredContentSize = .init(width: 200, height: 200) modalPresentationStyle = .overCurrentContext } @@ -69,8 +69,6 @@ class ModalDialogViewController: UIViewController { class ModalDialogTransition: SelfDismissingTransition { - required init() {} - func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] { let size = ctx.fore.view.frame.size let bounds = ctx.containerView().bounds @@ -106,7 +104,7 @@ class ModalDialogTransition: SelfDismissingTransition { return [tossable.spring] } - static func willPresent(fore: UIViewController, dismisser: ViewControllerDismisser) { + func willPresent(fore: UIViewController, dismisser: ViewControllerDismisser) { let tap = UITapGestureRecognizer() fore.view.addGestureRecognizer(tap) dismisser.dismissWhenGestureRecognizerBegins(tap) diff --git a/examples/PushBackTransitionExample.swift b/examples/PushBackTransitionExample.swift index 60da235..8cf2571 100644 --- a/examples/PushBackTransitionExample.swift +++ b/examples/PushBackTransitionExample.swift @@ -41,7 +41,7 @@ private class ModalViewController: UIViewController { override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - transitionController.transitionType = PushBackTransition.self + transitionController.transition = PushBackTransition() } required init?(coder aDecoder: NSCoder) { @@ -67,8 +67,6 @@ private class ModalViewController: UIViewController { private class PushBackTransition: Transition { - required init() {} - func willBeginTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) -> [Stateful] { let bounds = ctx.containerView().bounds let backPosition = bounds.maxY + ctx.fore.view.bounds.height / 2 diff --git a/examples/StickerPickerExample.swift b/examples/StickerPickerExample.swift index 895f679..31a83b4 100644 --- a/examples/StickerPickerExample.swift +++ b/examples/StickerPickerExample.swift @@ -108,7 +108,7 @@ private class StickerListViewController: UICollectionViewController { init() { super.init(collectionViewLayout: UICollectionViewFlowLayout()) - transitionController.transitionType = ModalTransition.self + transitionController.transition = ModalTransition() modalPresentationStyle = .overCurrentContext } diff --git a/src/transitions/Transition.swift b/src/transitions/Transition.swift index c61f43f..c37e229 100644 --- a/src/transitions/Transition.swift +++ b/src/transitions/Transition.swift @@ -18,10 +18,10 @@ import Foundation import UIKit /** - An object that is capable of responding to a transition that is about to begin. + A transition is responsible for describing the motion that will occur during a UIViewController + transition. */ -public protocol WillBeginTransition { - +public protocol Transition { /** Invoked on initiation of a view controller transition. @@ -34,12 +34,11 @@ public protocol WillBeginTransition { A transition is responsible for describing the motion that will occur during a UIViewController transition. */ -public protocol Transition: WillBeginTransition { - +public protocol TransitionWithTermination: Transition { /** - Transitions must be instantiable. + Invoked on completion of a view controller transition. */ - init() + func didEndTransition(withContext ctx: TransitionContext, runtime: MotionRuntime) } /** @@ -68,5 +67,5 @@ public protocol TransitionWithPresentation: Transition { cause the presented view controller to be dismissed. */ public protocol SelfDismissingTransition: Transition { - static func willPresent(fore: UIViewController, dismisser: ViewControllerDismisser) + func willPresent(fore: UIViewController, dismisser: ViewControllerDismisser) } diff --git a/src/transitions/TransitionContext.swift b/src/transitions/TransitionContext.swift index 06371b1..5ac3ca7 100644 --- a/src/transitions/TransitionContext.swift +++ b/src/transitions/TransitionContext.swift @@ -94,7 +94,7 @@ public final class TransitionContext: NSObject { weak var delegate: TransitionDelegate? - init(transitionType: Transition.Type, + init(transition: Transition, direction: TransitionDirection, back: UIViewController, fore: UIViewController, @@ -108,7 +108,7 @@ public final class TransitionContext: NSObject { self.window = TransitionTimeWindow(duration: TransitionContext.defaultDuration) self.presentationController = presentationController - self.transition = transitionType.init() + self.transition = transition super.init() } @@ -178,7 +178,7 @@ extension TransitionContext { var terminators = transition.willBeginTransition(withContext: self, runtime: self.runtime) - if let presentationController = presentationController as? WillBeginTransition { + if let presentationController = presentationController as? Transition { terminators.append(contentsOf: presentationController.willBeginTransition(withContext: self, runtime: self.runtime)) } @@ -251,6 +251,10 @@ extension TransitionContext { } context.completeTransition(completedInOriginalDirection) + if let transitionWithTermination = transition as? TransitionWithTermination { + transitionWithTermination.didEndTransition(withContext: self, runtime: runtime) + } + runtime = nil transition = nil diff --git a/src/transitions/TransitionController.swift b/src/transitions/TransitionController.swift index 52ef230..e575d74 100644 --- a/src/transitions/TransitionController.swift +++ b/src/transitions/TransitionController.swift @@ -63,9 +63,9 @@ public final class TransitionController { Must be a subclass of MDMTransition. */ - public var transitionType: Transition.Type? { - set { _transitioningDelegate.transitionType = newValue } - get { return _transitioningDelegate.transitionType } + public var transition: Transition? { + set { _transitioningDelegate.transition = newValue } + get { return _transitioningDelegate.transition } } /** @@ -164,7 +164,7 @@ private final class TransitioningDelegate: NSObject, UIViewControllerTransitioni } var ctx: TransitionContext? - var transitionType: Transition.Type? + var transition: Transition? let dismisser: ViewControllerDismisser let gestureDelegate = GestureDelegate() @@ -183,12 +183,12 @@ private final class TransitioningDelegate: NSObject, UIViewControllerTransitioni } assert(ctx == nil, "A transition is already active.") - if let transitionType = transitionType { - if direction == .forward, let selfDismissingDirector = transitionType as? SelfDismissingTransition.Type { + if let transition = transition { + if direction == .forward, let selfDismissingDirector = transition as? SelfDismissingTransition { selfDismissingDirector.willPresent(fore: fore, dismisser: dismisser) } - ctx = TransitionContext(transitionType: transitionType, + ctx = TransitionContext(transition: transition, direction: direction, back: back, fore: fore, @@ -245,15 +245,15 @@ private final class TransitioningDelegate: NSObject, UIViewControllerTransitioni } func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { - guard let transitionWithPresentation = transitionType as? TransitionWithPresentation.Type else { + guard let transitionWithPresentation = transition as? TransitionWithPresentation else { return nil } if let presentationController = presentationController { return presentationController } - presentationController = transitionWithPresentation.presentationController(forPresented: presented, - presenting: presenting, - source: source) + presentationController = type(of: transitionWithPresentation).presentationController(forPresented: presented, + presenting: presenting, + source: source) return presentationController } }