diff --git a/GarlandCollectionDemo/AppDelegate.swift b/GarlandCollectionDemo/AppDelegate.swift index 053fee1..4c887c7 100644 --- a/GarlandCollectionDemo/AppDelegate.swift +++ b/GarlandCollectionDemo/AppDelegate.swift @@ -1,10 +1,4 @@ -// -// AppDelegate.swift -// GarlandCollectionDemo -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import UIKit diff --git a/GarlandCollectionDemo/Extensions/UIView.swift b/GarlandCollectionDemo/Extensions/UIView.swift index fdf1d0e..472ac70 100644 --- a/GarlandCollectionDemo/Extensions/UIView.swift +++ b/GarlandCollectionDemo/Extensions/UIView.swift @@ -1,10 +1,4 @@ -// -// UIView.swift -// GarlandCollectionDemo -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit diff --git a/GarlandCollectionDemo/ViewControllers/Collections/CollectionCell.swift b/GarlandCollectionDemo/ViewControllers/Collections/CollectionCell.swift index 1054367..8d06886 100644 --- a/GarlandCollectionDemo/ViewControllers/Collections/CollectionCell.swift +++ b/GarlandCollectionDemo/ViewControllers/Collections/CollectionCell.swift @@ -1,10 +1,4 @@ -// -// CollectionCell.swift -// GarlandView -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit diff --git a/GarlandCollectionDemo/ViewControllers/Collections/HeaderView.swift b/GarlandCollectionDemo/ViewControllers/Collections/HeaderView.swift index 4282c42..194c559 100644 --- a/GarlandCollectionDemo/ViewControllers/Collections/HeaderView.swift +++ b/GarlandCollectionDemo/ViewControllers/Collections/HeaderView.swift @@ -1,3 +1,5 @@ +// Copyright © 2017 Ramotion. All rights reserved. + import Foundation import UIKit import GarlandView diff --git a/GarlandCollectionDemo/ViewControllers/Collections/ViewController.swift b/GarlandCollectionDemo/ViewControllers/Collections/ViewController.swift index 0e1bb97..5e377c3 100644 --- a/GarlandCollectionDemo/ViewControllers/Collections/ViewController.swift +++ b/GarlandCollectionDemo/ViewControllers/Collections/ViewController.swift @@ -1,10 +1,4 @@ -// -// ViewController.swift -// GarlandCollectionDemo -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import UIKit import GarlandView diff --git a/GarlandCollectionDemo/ViewControllers/UserCard/CardCollectionCell.swift b/GarlandCollectionDemo/ViewControllers/UserCard/CardCollectionCell.swift index 40b508a..a9116ff 100644 --- a/GarlandCollectionDemo/ViewControllers/UserCard/CardCollectionCell.swift +++ b/GarlandCollectionDemo/ViewControllers/UserCard/CardCollectionCell.swift @@ -1,10 +1,4 @@ -// -// CardCollectionCell.swift -// GarlandView -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit diff --git a/GarlandCollectionDemo/ViewControllers/UserCard/UserCardDismissAnimationController.swift b/GarlandCollectionDemo/ViewControllers/UserCard/UserCardDismissAnimationController.swift index 5ef4e82..0b22a62 100644 --- a/GarlandCollectionDemo/ViewControllers/UserCard/UserCardDismissAnimationController.swift +++ b/GarlandCollectionDemo/ViewControllers/UserCard/UserCardDismissAnimationController.swift @@ -1,10 +1,4 @@ -// -// GarlandCardDismissAnimationController.swift -// GarlandView -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit diff --git a/GarlandCollectionDemo/ViewControllers/UserCard/UserCardPresentAnimationController.swift b/GarlandCollectionDemo/ViewControllers/UserCard/UserCardPresentAnimationController.swift index ab62986..c4676b1 100644 --- a/GarlandCollectionDemo/ViewControllers/UserCard/UserCardPresentAnimationController.swift +++ b/GarlandCollectionDemo/ViewControllers/UserCard/UserCardPresentAnimationController.swift @@ -1,10 +1,4 @@ -// -// GarlandCardPresentAnimationController.swift -// GarlandView -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit diff --git a/GarlandCollectionDemo/ViewControllers/UserCard/UserCardViewController.swift b/GarlandCollectionDemo/ViewControllers/UserCard/UserCardViewController.swift index aa74e9e..54078cf 100644 --- a/GarlandCollectionDemo/ViewControllers/UserCard/UserCardViewController.swift +++ b/GarlandCollectionDemo/ViewControllers/UserCard/UserCardViewController.swift @@ -1,10 +1,4 @@ -// -// UserCardViewController.swift -// GarlandView -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit diff --git a/GarlandView.xcodeproj/project.pbxproj b/GarlandView.xcodeproj/project.pbxproj index 4f6fdda..87db33f 100644 --- a/GarlandView.xcodeproj/project.pbxproj +++ b/GarlandView.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 39465C8C2008F40600ADE9B3 /* UserCardPresentAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EDC226E1F00880A007C92E8 /* UserCardPresentAnimationController.swift */; }; 39465C8D2008F40600ADE9B3 /* UserCardDismissAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EDC22741F028782007C92E8 /* UserCardDismissAnimationController.swift */; }; + 39465C8F2009194900ADE9B3 /* GarlandTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39465C8E2009194900ADE9B3 /* GarlandTransitioningDelegate.swift */; }; 3986967B2007B4C30066E0C6 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3986967A2007B4C30066E0C6 /* HeaderView.swift */; }; 3986967D2007B5310066E0C6 /* HeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3986967C2007B5310066E0C6 /* HeaderView.xib */; }; 39A59C892004C468007F8ECF /* UserCardViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 39A59C7F2004C468007F8ECF /* UserCardViewController.xib */; }; @@ -27,7 +28,7 @@ 4E0EB0961EEECDED00DD634C /* GarlandView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E0EB0591EED8D1300DD634C /* GarlandView.framework */; }; 4E0EB0971EEECDED00DD634C /* GarlandView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4E0EB0591EED8D1300DD634C /* GarlandView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4EC9B06B1EF2F4A500A0A0AF /* GarlandViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC9B06A1EF2F4A400A0A0AF /* GarlandViewController.swift */; }; - 4EC9B06D1EF2F68E00A0A0AF /* GarlandPresentAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC9B06C1EF2F68E00A0A0AF /* GarlandPresentAnimationController.swift */; }; + 4EC9B06D1EF2F68E00A0A0AF /* GarlandAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC9B06C1EF2F68E00A0A0AF /* GarlandAnimationController.swift */; }; 4EF4A6E21F8BB6B60094BADF /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF4A6E11F8BB6B60094BADF /* UIView.swift */; }; /* End PBXBuildFile section */ @@ -56,6 +57,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 39465C8E2009194900ADE9B3 /* GarlandTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarlandTransitioningDelegate.swift; sourceTree = ""; }; 3986967A2007B4C30066E0C6 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 3986967C2007B5310066E0C6 /* HeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HeaderView.xib; sourceTree = ""; }; 39A59C7F2004C468007F8ECF /* UserCardViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UserCardViewController.xib; sourceTree = ""; }; @@ -76,7 +78,7 @@ 4E0EB07E1EEEB81000DD634C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4E8475181F05880C0016CDBA /* CardCollectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardCollectionCell.swift; sourceTree = ""; }; 4EC9B06A1EF2F4A400A0A0AF /* GarlandViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GarlandViewController.swift; sourceTree = ""; }; - 4EC9B06C1EF2F68E00A0A0AF /* GarlandPresentAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GarlandPresentAnimationController.swift; sourceTree = ""; }; + 4EC9B06C1EF2F68E00A0A0AF /* GarlandAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GarlandAnimationController.swift; sourceTree = ""; }; 4EDC226E1F00880A007C92E8 /* UserCardPresentAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserCardPresentAnimationController.swift; sourceTree = ""; }; 4EDC22741F028782007C92E8 /* UserCardDismissAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserCardDismissAnimationController.swift; sourceTree = ""; }; 4EF4A6E11F8BB6B60094BADF /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UIView.swift; path = Extensions/UIView.swift; sourceTree = ""; }; @@ -104,7 +106,8 @@ 39869674200604010066E0C6 /* Transitions */ = { isa = PBXGroup; children = ( - 4EC9B06C1EF2F68E00A0A0AF /* GarlandPresentAnimationController.swift */, + 4EC9B06C1EF2F68E00A0A0AF /* GarlandAnimationController.swift */, + 39465C8E2009194900ADE9B3 /* GarlandTransitioningDelegate.swift */, ); name = Transitions; sourceTree = ""; @@ -356,8 +359,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4EC9B06D1EF2F68E00A0A0AF /* GarlandPresentAnimationController.swift in Sources */, + 4EC9B06D1EF2F68E00A0A0AF /* GarlandAnimationController.swift in Sources */, 4E0EB0671EED8E5100DD634C /* GarlandCollection.swift in Sources */, + 39465C8F2009194900ADE9B3 /* GarlandTransitioningDelegate.swift in Sources */, 4EC9B06B1EF2F4A500A0A0AF /* GarlandViewController.swift in Sources */, 4E0EB06A1EED8F9F00DD634C /* GarlandConfig.swift in Sources */, ); diff --git a/GarlandView/GarlandPresentAnimationController.swift b/GarlandView/GarlandAnimationController.swift similarity index 88% rename from GarlandView/GarlandPresentAnimationController.swift rename to GarlandView/GarlandAnimationController.swift index c242b1c..8107951 100644 --- a/GarlandView/GarlandPresentAnimationController.swift +++ b/GarlandView/GarlandAnimationController.swift @@ -1,21 +1,17 @@ -// -// GarlandPresentAnimationController.swift -// GarlandView -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit -public class GarlandPresentAnimationController: NSObject, UIViewControllerAnimatedTransitioning { +public class GarlandAnimationController: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning { public enum TransitionDirection { case left case right } + var isInteractive: Bool = false + var transitionDirection: TransitionDirection = .right private var finalFromXFrame: CGFloat { return transitionDirection == .right ? UIScreen.main.bounds.width : 0 @@ -136,7 +132,7 @@ public class GarlandPresentAnimationController: NSObject, UIViewControllerAnimat overlappedCells.forEach { $0.alpha = 0 } }) - UIView.addKeyframe(withRelativeStartTime: 0.1, relativeDuration: 0.8, animations: { + UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0, animations: { fromHeaderSnapshot.frame = headerFromFrame toHeaderSnapshot.frame = headerFinalFrame @@ -144,6 +140,7 @@ public class GarlandPresentAnimationController: NSObject, UIViewControllerAnimat fromHeaderSnapshot.alpha = 0.2 toHeaderSnapshot.alpha = 1 + toFakeHeader.frame = headerFinalFrame fromFakeHeader.transform = CGAffineTransform(translationX: headerStartFrame.midX - headerToFrame.midX, y: 0) for (index, snapshot) in visibleToSnapshots.enumerated() { @@ -185,10 +182,34 @@ public class GarlandPresentAnimationController: NSObject, UIViewControllerAnimat } fromHeaderSnapshot.removeFromSuperview() toHeaderSnapshot.removeFromSuperview() - fromVC.view.removeFromSuperview() + if !transitionContext.transitionWasCancelled { + fromVC.view.removeFromSuperview() + } else { + fromVC.headerView.alpha = 1 + fromVC.garlandCollection.alpha = 1 + fromVC.isPresenting = false + } transitionContext.completeTransition(!transitionContext.transitionWasCancelled) }) } + + func handleInteractiveTranslaition(_ translation: CGFloat, state: UIGestureRecognizerState) { + + let distance = UIScreen.main.bounds.width + let directedTranslation = transitionDirection == .left ? -translation : translation + let d = min(max(0, (directedTranslation / distance)), 1) + + switch (state) { + case .began, .changed: + update(d) + + let translationThreshold: CGFloat = 0.35 + if d >= translationThreshold { finish() } + default: // .Ended, .Cancelled, .Failed ... + isInteractive = false + cancel() + } + } } struct AnimationHelper { diff --git a/GarlandView/GarlandCollection.swift b/GarlandView/GarlandCollection.swift index 8d5e4ef..d88e3c6 100644 --- a/GarlandView/GarlandCollection.swift +++ b/GarlandView/GarlandCollection.swift @@ -1,10 +1,4 @@ -// -// GarlandCollectionViewController.swift -// garland-view -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit diff --git a/GarlandView/GarlandConfig.swift b/GarlandView/GarlandConfig.swift index d963e2d..429f3de 100644 --- a/GarlandView/GarlandConfig.swift +++ b/GarlandView/GarlandConfig.swift @@ -1,10 +1,4 @@ -// -// GarlandConfig.swift -// GarlandView -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import UIKit diff --git a/GarlandView/GarlandTransitioningDelegate.swift b/GarlandView/GarlandTransitioningDelegate.swift new file mode 100644 index 0000000..0e6b226 --- /dev/null +++ b/GarlandView/GarlandTransitioningDelegate.swift @@ -0,0 +1,24 @@ +// Copyright © 2017 Ramotion. All rights reserved. + +import Foundation + +open class GarlandTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate { + + let animationController = GarlandAnimationController() + + public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + return animationController + } + + public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + return animationController + } + + public func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { + return animationController.isInteractive ? animationController : nil + } + + public func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { + return animationController.isInteractive ? animationController : nil + } +} diff --git a/GarlandView/GarlandViewController.swift b/GarlandView/GarlandViewController.swift index 150271a..00f846b 100644 --- a/GarlandView/GarlandViewController.swift +++ b/GarlandView/GarlandViewController.swift @@ -1,17 +1,11 @@ -// -// garlandCollectionController.swift -// garlandCollection -// -// Created by Slava Yusupov. -// Copyright © 2017 Ramotion. All rights reserved. -// +// Copyright © 2017 Ramotion. All rights reserved. import Foundation import UIKit open class GarlandViewController: UIViewController { - public var nextViewController: ((GarlandPresentAnimationController.TransitionDirection) -> GarlandViewController)? + public var nextViewController: ((GarlandAnimationController.TransitionDirection) -> GarlandViewController)? public let garlandCollection = GarlandCollection() public var backgroundHeader = UIView() @@ -22,46 +16,27 @@ open class GarlandViewController: UIViewController { open var animationXDest: CGFloat = 0.0 open var selectedCardIndex: IndexPath = IndexPath() - open var isPresenting = false + internal var isPresenting = false + + private var transitionDelegate: GarlandTransitioningDelegate? - fileprivate let garlandPresentAnimationController = GarlandPresentAnimationController() - override open func viewDidLoad() { super.viewDidLoad() - modalPresentationStyle = .custom - transitioningDelegate = self - //setup garland collection view garlandCollection.frame = CGRect(x: 0, y: GarlandConfig.shared.headerVerticalOffset, width: view.bounds.width, height: view.bounds.height - GarlandConfig.shared.headerVerticalOffset) garlandCollection.autoresizingMask = [.flexibleWidth, .flexibleHeight] + garlandCollection.panGestureRecognizer.cancelsTouchesInView = false + garlandCollection.panGestureRecognizer.delaysTouchesBegan = false view.addSubview(garlandCollection) setupBackground() setupFakeHeaders() - - //add horizontal pan gesture recognizer - let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handleGesture)) - view.addGestureRecognizer(panGesture) - } - - @objc func handleGesture(gesture: UIPanGestureRecognizer) { - let velocity = gesture.velocity(in: view) - let translation = gesture.translation(in: view) - - if velocity.x > 0, translation.x > 15 { - performTransition(direction: .right) - } else if translation.x < -15 { - performTransition(direction: .left) - } } - private func performTransition(direction: GarlandPresentAnimationController.TransitionDirection) { - guard !isPresenting else { return } - guard let vc = nextViewController?(direction) else { return } - isPresenting = true - vc.garlandPresentAnimationController.transitionDirection = direction - present(vc, animated: true, completion: nil) + //MARK: Public methods + public func performTransition(direction: GarlandAnimationController.TransitionDirection) { + performTransition(direction: direction, isInteractive: false) } open func setupHeader(_ headerView: UIView) { @@ -76,11 +51,73 @@ open class GarlandViewController: UIViewController { } } +var startPoint: CGPoint? = nil -//MARK: Setup -public extension GarlandViewController { + +//MARK: Transition methods +extension GarlandViewController: UIGestureRecognizerDelegate { + + open override func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard let location = touches.first?.location(in: view) else { return } + startPoint = location + } - fileprivate func setupBackground() { + open override func touchesMoved(_ touches: Set, with event: UIEvent?) { + guard let location = touches.first?.location(in: view) else { return } + handleMovement(location: location, state: UIGestureRecognizerState.changed) + } + + open override func touchesEnded(_ touches: Set, with event: UIEvent?) { + guard let location = touches.first?.location(in: view) else { return } + handleMovement(location: location, state: UIGestureRecognizerState.ended) + startPoint = nil + } + + open override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + guard let location = touches.first?.location(in: view) else { return } + handleMovement(location: location, state: UIGestureRecognizerState.cancelled) + startPoint = nil + } + + private func handleMovement(location: CGPoint, state: UIGestureRecognizerState) { + guard let start = startPoint else { return } + let translation = location.x - start.x + + if abs(translation) > 0 { + let direction: GarlandAnimationController.TransitionDirection = translation > 0 ? .right : .left + performTransition(direction: direction, isInteractive: true) + } + + if let presentedVC = (presentedViewController as? GarlandViewController), + let transitionDelegate = presentedVC.transitioningDelegate as? GarlandTransitioningDelegate { + transitionDelegate.animationController.handleInteractiveTranslaition(translation, state: state) + } + } + + private func performTransition(direction: GarlandAnimationController.TransitionDirection, isInteractive: Bool) { + guard !isPresenting else { return } + guard let vc = nextViewController?(direction) else { return } + isPresenting = true + + let transitionDelegate = GarlandTransitioningDelegate() + transitionDelegate.animationController.transitionDirection = direction + transitionDelegate.animationController.isInteractive = isInteractive + if #available(iOS 10.0, *) { + transitionDelegate.animationController.wantsInteractiveStart = isInteractive + } + vc.modalPresentationStyle = .custom + vc.transitionDelegate = transitionDelegate + vc.transitioningDelegate = transitionDelegate + + present(vc, animated: true, completion: nil) + } +} + + +//MARK: Setup & configuration methods +private extension GarlandViewController { + + private func setupBackground() { let config = GarlandConfig.shared backgroundHeader.frame.size = CGSize(width: UIScreen.main.bounds.width, height: config.backgroundHeaderHeight) backgroundHeader.frame.origin.x = 0 @@ -89,7 +126,7 @@ public extension GarlandViewController { view.insertSubview(backgroundHeader, at: 0) } - fileprivate func setupFakeHeaders() { + private func setupFakeHeaders() { let config = GarlandConfig.shared let size = CGSize(width: config.headerSize.width/1.6, height: config.headerSize.height/1.6) let verticalPosition = garlandCollection.frame.origin.y + (GarlandConfig.shared.headerSize.height - size.height)/2 @@ -109,14 +146,3 @@ public extension GarlandViewController { view.addSubview(leftFakeHeader) } } - -extension GarlandViewController: UIViewControllerTransitioningDelegate { - - public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return garlandPresentAnimationController - } - - public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return garlandPresentAnimationController - } -}