diff --git a/PanModal/Animator/PanModalPresentationAnimator.swift b/PanModal/Animator/PanModalPresentationAnimator.swift index d31b43db..18feed0e 100644 --- a/PanModal/Animator/PanModalPresentationAnimator.swift +++ b/PanModal/Animator/PanModalPresentationAnimator.swift @@ -50,17 +50,11 @@ public class PanModalPresentationAnimator: NSObject { */ private func animatePresentation(transitionContext: UIViewControllerContextTransitioning) { - guard let toVC = transitionContext.viewController(forKey: .to), let fromVC = transitionContext.viewController(forKey: .from) + guard let toVC = transitionContext.viewController(forKey: .to) else { return } let presentable = toVC as? PanModalPresentable.LayoutType - // Calls viewWillAppear and viewWillDisappear - if presentable?.shouldTriggerLifecycleMethods == true { - fromVC.beginAppearanceTransition(false, animated: true) - toVC.beginAppearanceTransition(true, animated: true) - } - // Presents the view in shortForm position, initially let yPos: CGFloat = presentable?.shortFormYPos ?? 0.0 @@ -86,13 +80,8 @@ public class PanModalPresentationAnimator: NSObject { topView?.frame.origin.y = yPos - topViewHeight topView?.alpha = 1 }, config: presentable) { didComplete in - if presentable?.shouldTriggerLifecycleMethods == true { - fromVC.endAppearanceTransition() - toVC.endAppearanceTransition() - } transitionContext.completeTransition(didComplete) } - } /** @@ -100,7 +89,7 @@ public class PanModalPresentationAnimator: NSObject { */ private func animateDismissal(transitionContext: UIViewControllerContextTransitioning) { - guard let fromVC = transitionContext.viewController(forKey: .from), let toVC = transitionContext.viewController(forKey: .to) + guard let fromVC = transitionContext.viewController(forKey: .from) else { return } let presentable = fromVC as? PanModalPresentable.LayoutType @@ -114,23 +103,12 @@ public class PanModalPresentationAnimator: NSObject { } }() - // Calls viewWillAppear and viewWillDisappear - if presentable?.shouldTriggerLifecycleMethods == true { - fromVC.beginAppearanceTransition(false, animated: true) - toVC.beginAppearanceTransition(true, animated: true) - } - PanModalAnimator.animate({ panView.frame.origin.y = transitionContext.containerView.frame.height + PanModalPresentationController.Constants.dragIndicatorHeight + topViewHeight topView?.frame.origin.y = transitionContext.containerView.frame.height topView?.alpha = 0.0 }, config: presentable) { didComplete in fromVC.view.removeFromSuperview() - // Calls viewDidAppear and viewDidDisappear - if presentable?.shouldTriggerLifecycleMethods == true { - fromVC.endAppearanceTransition() - toVC.endAppearanceTransition() - } transitionContext.completeTransition(didComplete) } } diff --git a/PanModal/Controller/PanModalNavigationController.swift b/PanModal/Controller/PanModalNavigationController.swift index 21171700..afc54676 100644 --- a/PanModal/Controller/PanModalNavigationController.swift +++ b/PanModal/Controller/PanModalNavigationController.swift @@ -25,9 +25,6 @@ public class PanModalNavigationController: UINavigationController, PanModalPrese public var panModalBackgroundColor: UIColor { UIColor.black.withAlphaComponent(0.7) } - public var shouldTriggerLifecycleMethods: Bool { - shouldTriggerLifecycleMethodsWhenPresentModal - } public var dragIndicatorBackgroundColor: UIColor { .Palette.surface } @@ -44,7 +41,6 @@ public class PanModalNavigationController: UINavigationController, PanModalPrese return topViewController as? PanModalPresentable } private var borderCoordinator: BorderCoordinator? - private var shouldTriggerLifecycleMethodsWhenPresentModal = false public override func viewDidLoad() { super.viewDidLoad() @@ -110,10 +106,6 @@ public class PanModalNavigationController: UINavigationController, PanModalPrese presentable.panModalWillDismiss() } } - - public func setPanModalLifecycle(_ enabled: Bool) { - shouldTriggerLifecycleMethodsWhenPresentModal = enabled - } } extension PanModalNavigationController: UINavigationControllerDelegate { diff --git a/PanModal/Controller/PanModalPresentationController+Event.swift b/PanModal/Controller/PanModalPresentationController+Event.swift new file mode 100644 index 00000000..8a28d4f9 --- /dev/null +++ b/PanModal/Controller/PanModalPresentationController+Event.swift @@ -0,0 +1,33 @@ +import UIKit +import Combine + +extension PanModalPresentationController { + // MARK: - Internal Event Emitters + func notifyWillPresent() { + (presentedViewController as? PanModalPresentable)?.panModalWillPresent() + if #available(iOS 13.0, *) { + PanModalLifeCycleEventPublisher.shared.notify(.willPresent(viewController: presentedViewController)) + } + } + + func notifyDidPresent() { + (presentedViewController as? PanModalPresentable)?.panModalDidPresent() + if #available(iOS 13.0, *) { + PanModalLifeCycleEventPublisher.shared.notify(.didPresent(viewController: presentedViewController)) + } + } + + func notifyWillDismiss() { + (presentedViewController as? PanModalPresentable)?.panModalWillDismiss() + if #available(iOS 13.0, *) { + PanModalLifeCycleEventPublisher.shared.notify(.willDismiss(viewController: presentedViewController)) + } + } + + func notifyDidDismiss() { + (presentedViewController as? PanModalPresentable)?.panModalDidDismiss() + if #available(iOS 13.0, *) { + PanModalLifeCycleEventPublisher.shared.notify(.didDismiss(viewController: presentedViewController)) + } + } +} diff --git a/PanModal/Controller/PanModalPresentationController.swift b/PanModal/Controller/PanModalPresentationController.swift index f161d752..69f603ee 100644 --- a/PanModal/Controller/PanModalPresentationController.swift +++ b/PanModal/Controller/PanModalPresentationController.swift @@ -171,6 +171,8 @@ public class PanModalPresentationController: UIPresentationController { guard let containerView = containerView else { return } + + notifyWillPresent() layoutBackgroundView(in: containerView) layoutPresentedView(in: containerView) @@ -188,6 +190,7 @@ public class PanModalPresentationController: UIPresentationController { } override public func dismissalTransitionWillBegin() { + notifyWillDismiss() guard let coordinator = presentedViewController.transitionCoordinator else { backgroundView.dimState = .off @@ -206,7 +209,10 @@ public class PanModalPresentationController: UIPresentationController { } override public func presentationTransitionDidEnd(_ completed: Bool) { - if completed { return } + if completed { + notifyDidPresent() + return + } presentable?.panCustomTopView?.removeFromSuperview() backgroundView.removeFromSuperview() @@ -222,6 +228,12 @@ public class PanModalPresentationController: UIPresentationController { self?.adjustPresentedViewFrame() }) } + + public override func dismissalTransitionDidEnd(_ completed: Bool) { + if completed { + notifyDidDismiss() + } + } } diff --git a/PanModal/Event/PanModalLifeCycleEvent.swift b/PanModal/Event/PanModalLifeCycleEvent.swift new file mode 100644 index 00000000..15e49879 --- /dev/null +++ b/PanModal/Event/PanModalLifeCycleEvent.swift @@ -0,0 +1,21 @@ +import Combine + +public enum PanModalLifeCycleEvent { + case willPresent(viewController: UIViewController) + case didPresent(viewController: UIViewController) + case willDismiss(viewController: UIViewController) + case didDismiss(viewController: UIViewController) +} + +@available(iOS 13.0, *) +public final class PanModalLifeCycleEventPublisher { + public static let shared = PanModalLifeCycleEventPublisher() + + public let publisher = PassthroughSubject() + + private init() {} + + func notify(_ event: PanModalLifeCycleEvent) { + publisher.send(event) + } +} diff --git a/PanModal/Presentable/PanModalPresentable+Defaults.swift b/PanModal/Presentable/PanModalPresentable+Defaults.swift index 9a335828..ca03c9ef 100644 --- a/PanModal/Presentable/PanModalPresentable+Defaults.swift +++ b/PanModal/Presentable/PanModalPresentable+Defaults.swift @@ -85,10 +85,6 @@ public extension PanModalPresentable where Self: UIViewController { return nil } - var shouldTriggerLifecycleMethods: Bool { - return false - } - var indicatorColor: UIColor { return UIColor(red: 241/255.0, green: 243/255.0, blue: 245/255.0, alpha: 1) } @@ -111,6 +107,14 @@ public extension PanModalPresentable where Self: UIViewController { func willTransition(to state: PanModalPresentationState) { + } + + func panModalWillPresent() { + + } + + func panModalDidPresent() { + } func panModalWillDismiss() { diff --git a/PanModal/Presentable/PanModalPresentable.swift b/PanModal/Presentable/PanModalPresentable.swift index 2ddaecad..a1dc26dd 100644 --- a/PanModal/Presentable/PanModalPresentable.swift +++ b/PanModal/Presentable/PanModalPresentable.swift @@ -144,14 +144,6 @@ public protocol PanModalPresentable { var indicatorColor: UIColor { get } var panCustomTopView: PanCustomTopView? { get } - - /** - A flag to determine if viewController lifecycle methods should be called - during presentation and dismissal. - - Default value is false for backwards compatibility. - */ - var shouldTriggerLifecycleMethods: Bool { get } /** Asks the delegate if the pan modal should respond to the pan modal gesture recognizer. @@ -200,6 +192,15 @@ public protocol PanModalPresentable { */ func willTransition(to state: PanModalPresentationState) + /** + Notifies the delegate that the pan modal is about to be presented. + + Default value is an empty implementation. + */ + func panModalWillPresent() + + func panModalDidPresent() + /** Notifies the delegate that the pan modal is about to be dismissed. diff --git a/PanModalDemo.xcodeproj/project.pbxproj b/PanModalDemo.xcodeproj/project.pbxproj index fd1e034a..3564f5a3 100644 --- a/PanModalDemo.xcodeproj/project.pbxproj +++ b/PanModalDemo.xcodeproj/project.pbxproj @@ -66,6 +66,10 @@ DC3B2EBE222A58C9000C8A4A /* AlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3B2EBD222A58C9000C8A4A /* AlertView.swift */; }; DCA741AE216D90410021F2F2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA741AD216D90410021F2F2 /* AppDelegate.swift */; }; DCC0EE7C21917F2500208DBC /* PanModalPresentable+Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC0EE7B21917F2500208DBC /* PanModalPresentable+Defaults.swift */; }; + FD72B2902D5AF19400441991 /* PanModalLifeCycleEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD72B28F2D5AF19400441991 /* PanModalLifeCycleEvent.swift */; }; + FD72B2912D5AF19400441991 /* PanModalLifeCycleEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD72B28F2D5AF19400441991 /* PanModalLifeCycleEvent.swift */; }; + FD72B2932D5AF65400441991 /* PanModalPresentationController+Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD72B2922D5AF65400441991 /* PanModalPresentationController+Event.swift */; }; + FD72B2942D5AF65400441991 /* PanModalPresentationController+Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD72B2922D5AF65400441991 /* PanModalPresentationController+Event.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -145,6 +149,8 @@ DCA741AD216D90410021F2F2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DCA741B9216D90420021F2F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DCC0EE7B21917F2500208DBC /* PanModalPresentable+Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PanModalPresentable+Defaults.swift"; sourceTree = ""; }; + FD72B28F2D5AF19400441991 /* PanModalLifeCycleEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanModalLifeCycleEvent.swift; sourceTree = ""; }; + FD72B2922D5AF65400441991 /* PanModalPresentationController+Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PanModalPresentationController+Event.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -279,6 +285,7 @@ DC139065216D9458007A3E64 /* Animator */, DC13906B216D9458007A3E64 /* Controller */, DC139063216D9458007A3E64 /* Delegate */, + FD72B28E2D5AF17B00441991 /* Event */, DC139067216D9458007A3E64 /* Presentable */, 74C072A8220BA80700124CE1 /* Presenter */, DC13906D216D9458007A3E64 /* View */, @@ -322,6 +329,7 @@ 638A937F256B4DC500A5E00B /* PanModalWrappedViewController.swift */, DC13906C216D9458007A3E64 /* PanModalPresentationController.swift */, 6ED0BEA82BE4BA110094D900 /* OverContextNavigationController.swift */, + FD72B2922D5AF65400441991 /* PanModalPresentationController+Event.swift */, ); path = Controller; sourceTree = ""; @@ -400,6 +408,14 @@ path = Sample; sourceTree = ""; }; + FD72B28E2D5AF17B00441991 /* Event */ = { + isa = PBXGroup; + children = ( + FD72B28F2D5AF19400441991 /* PanModalLifeCycleEvent.swift */, + ); + path = Event; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -558,6 +574,8 @@ 0F2A2C652239C151003BDB2F /* PanModalPresentable+UIViewController.swift in Sources */, 6ED0BEA72BE4B9DF0094D900 /* OverContextPanModalPresentable.swift in Sources */, 0F2A2C662239C153003BDB2F /* PanModalPresentable+LayoutHelpers.swift in Sources */, + FD72B2932D5AF65400441991 /* PanModalPresentationController+Event.swift in Sources */, + FD72B2912D5AF19400441991 /* PanModalLifeCycleEvent.swift in Sources */, 0F2A2C672239C157003BDB2F /* PanModalPresenter.swift in Sources */, D134CC7122641B350022AA29 /* IndicatorView.swift in Sources */, 638A9380256B4DC500A5E00B /* PanModalWrappedViewController.swift in Sources */, @@ -583,6 +601,7 @@ D134CC7222641B6E0022AA29 /* IndicatorView.swift in Sources */, 743CABB42225FE7700634A5A /* UserGroupMemberPresentable.swift in Sources */, 74C072A3220BA6E500124CE1 /* PanModalAnimator.swift in Sources */, + FD72B2942D5AF65400441991 /* PanModalPresentationController+Event.swift in Sources */, 743CABB8222600C600634A5A /* UserGroupMemberCell.swift in Sources */, 743CABB62225FEEE00634A5A /* UserGroupHeaderPresentable.swift in Sources */, 743CB2AA222660D100665A55 /* StackedProfileViewController.swift in Sources */, @@ -604,6 +623,7 @@ DC139061216D93ED007A3E64 /* SampleViewController.swift in Sources */, 743CABB02225FC9F00634A5A /* UserGroupViewController.swift in Sources */, 638A938D256BB26E00A5E00B /* EmbedViewController.swift in Sources */, + FD72B2902D5AF19400441991 /* PanModalLifeCycleEvent.swift in Sources */, 6E763B4D2A2E25A2002A77E8 /* CustomTopView.swift in Sources */, DCC0EE7C21917F2500208DBC /* PanModalPresentable+Defaults.swift in Sources */, 94795C9D21F03368008045A0 /* PanContainerView.swift in Sources */,