From 4c04c841c308adfb3b2e2fa7e06a874483dc2e20 Mon Sep 17 00:00:00 2001 From: agates4 Date: Thu, 19 Jan 2017 14:18:58 -0500 Subject: [PATCH 01/23] forked and added changes (tab feature and restore view controller feature) --- Pod/Classes/SideMenuManager.swift | 28 ++++++---- .../UISideMenuNavigationController.swift | 51 +++++++++++++++++-- README.md | 6 +++ 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index 6cfd21d..efc411e 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -6,15 +6,15 @@ // /* Example usage: - // Define the menus - SideMenuManager.menuLeftNavigationController = storyboard!.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as? UISideMenuNavigationController - SideMenuManager.menuRightNavigationController = storyboard!.instantiateViewController(withIdentifier: "RightMenuNavigationController") as? UISideMenuNavigationController - - // Enable gestures. The left and/or right menus must be set up above for these to work. - // Note that these continue to work on the Navigation Controller independent of the View Controller it displays! - SideMenuManager.menuAddPanGestureToPresent(toView: self.navigationController!.navigationBar) - SideMenuManager.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController!.view) -*/ + // Define the menus + SideMenuManager.menuLeftNavigationController = storyboard!.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as? UISideMenuNavigationController + SideMenuManager.menuRightNavigationController = storyboard!.instantiateViewController(withIdentifier: "RightMenuNavigationController") as? UISideMenuNavigationController + + // Enable gestures. The left and/or right menus must be set up above for these to work. + // Note that these continue to work on the Navigation Controller independent of the View Controller it displays! + SideMenuManager.menuAddPanGestureToPresent(toView: self.navigationController!.navigationBar) + SideMenuManager.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController!.view) + */ open class SideMenuManager : NSObject { @@ -30,7 +30,7 @@ open class SideMenuManager : NSObject { let appWindowRect = UIApplication.shared.keyWindow?.bounds ?? UIWindow().bounds return appWindowRect } - + /** The presentation mode of the menu. @@ -42,6 +42,12 @@ open class SideMenuManager : NSObject { */ open static var menuPresentMode: MenuPresentMode = .viewSlideOut + /// Retrieves each already created view controller to front when called. Requires class restoration identifiers. Defaults to false. + open static var menuPreserveViewOnPush = false + + /// Mimics a tab function, by instantly presenting the view controller. Defaults to false. + open static var menuTabMode = false + /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. open static var menuAllowPushOfSameClassTwice = true @@ -251,7 +257,7 @@ open class SideMenuManager : NSObject { - Parameter toView: The view to add gestures to. - Parameter forMenu: The menu (left or right) you want to add a gesture for. If unspecified, gestures will be added for both sides. - + - Returns: The array of screen edge gestures added to `toView`. */ @discardableResult open class func menuAddScreenEdgePanGesturesToPresent(toView: UIView, forMenu:UIRectEdge? = nil) -> [UIScreenEdgePanGestureRecognizer] { diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index 31adf2a..f3a3366 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -97,22 +97,22 @@ open class UISideMenuNavigationController: UINavigationController { SideMenuTransition.statusBarView?.isHidden = true coordinator.animate(alongsideTransition: { (context) -> Void in SideMenuTransition.presentMenuStart(forSize: size) - }) { (context) -> Void in - SideMenuTransition.statusBarView?.isHidden = false + }) { (context) -> Void in + SideMenuTransition.statusBarView?.isHidden = false } } override open func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let menuViewController: UINavigationController = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController, let presentingViewController = menuViewController.presentingViewController as? UINavigationController { - presentingViewController.prepare(for: segue, sender: sender) + presentingViewController.prepare(for: segue, sender: sender) } } override open func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if let menuViewController: UINavigationController = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController, let presentingViewController = menuViewController.presentingViewController as? UINavigationController { - return presentingViewController.shouldPerformSegue(withIdentifier: identifier, sender: sender) + return presentingViewController.shouldPerformSegue(withIdentifier: identifier, sender: sender) } return super.shouldPerformSegue(withIdentifier: identifier, sender: sender) @@ -125,7 +125,7 @@ open class UISideMenuNavigationController: UINavigationController { super.pushViewController(viewController, animated: animated) return } - + let tabBarController = presentingViewController as? UITabBarController guard let navigationController = (tabBarController?.selectedViewController ?? presentingViewController) as? UINavigationController else { print("SideMenu Warning: attempt to push a View Controller from \(presentingViewController.self) where its navigationController == nil. It must be embedded in a Navigation Controller for this to work.") @@ -147,6 +147,11 @@ open class UISideMenuNavigationController: UINavigationController { if SideMenuManager.menuAllowPopIfPossible { for subViewController in navigationController.viewControllers { if type(of: subViewController) == type(of: viewController) { + if SideMenuManager.menuTabMode { + navigationController.popToViewController(subViewController, animated: false) + CATransaction.commit() + return + } navigationController.popToViewController(subViewController, animated: animated) CATransaction.commit() return @@ -154,10 +159,40 @@ open class UISideMenuNavigationController: UINavigationController { } } + if SideMenuManager.menuPreserveViewOnPush { + var viewControllers = navigationController.viewControllers + let filtered = viewControllers.filter{$0.restorationIdentifier == viewController.restorationIdentifier} + if let preservedView = filtered.first { + viewControllers = viewControllers.filter() { $0 !== preservedView } + viewControllers.append(preservedView) + if SideMenuManager.menuTabMode { + navigationController.setViewControllers(viewControllers, animated: false) + CATransaction.commit() + return + } + navigationController.setViewControllers(viewControllers, animated: animated) + CATransaction.commit() + return + } + if SideMenuManager.menuTabMode { + navigationController.pushViewController(viewController, animated: false) + CATransaction.commit() + return + } + navigationController.pushViewController(viewController, animated: animated) + CATransaction.commit() + return + } + if SideMenuManager.menuReplaceOnPush { var viewControllers = navigationController.viewControllers viewControllers.removeLast() viewControllers.append(viewController) + if SideMenuManager.menuTabMode { + navigationController.setViewControllers(viewControllers, animated: false) + CATransaction.commit() + return + } navigationController.setViewControllers(viewControllers, animated: animated) CATransaction.commit() return @@ -168,6 +203,12 @@ open class UISideMenuNavigationController: UINavigationController { return } + if SideMenuManager.menuTabMode { + navigationController.pushViewController(viewController, animated: false) + CATransaction.commit() + return + } + navigationController.pushViewController(viewController, animated: animated) CATransaction.commit() } diff --git a/README.md b/README.md index a502324..f38b96c 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,12 @@ There are four modes in MenuPresentMode: */ open static var menuPresentMode: MenuPresentMode = .viewSlideOut +/// Retrieves each already created view controller to front when called. Requires class restoration identifiers. Defaults to false. +open static var menuPreserveViewOnPush = false + +/// Mimics a tab function, by instantly presenting the view controller. Defaults to false. +open static var menuTabMode = false + /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. open static var menuAllowPushOfSameClassTwice = true From f15081a31bd28e7986ea35ec6e76ffb2708f76b4 Mon Sep 17 00:00:00 2001 From: agates4 Date: Thu, 19 Jan 2017 14:23:47 -0500 Subject: [PATCH 02/23] fixed spacing / indentation issues --- Pod/Classes/SideMenuManager.swift | 20 +++++++++---------- .../UISideMenuNavigationController.swift | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index efc411e..945878f 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -6,14 +6,14 @@ // /* Example usage: - // Define the menus - SideMenuManager.menuLeftNavigationController = storyboard!.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as? UISideMenuNavigationController - SideMenuManager.menuRightNavigationController = storyboard!.instantiateViewController(withIdentifier: "RightMenuNavigationController") as? UISideMenuNavigationController - - // Enable gestures. The left and/or right menus must be set up above for these to work. - // Note that these continue to work on the Navigation Controller independent of the View Controller it displays! - SideMenuManager.menuAddPanGestureToPresent(toView: self.navigationController!.navigationBar) - SideMenuManager.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController!.view) + // Define the menus + SideMenuManager.menuLeftNavigationController = storyboard!.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as? UISideMenuNavigationController + SideMenuManager.menuRightNavigationController = storyboard!.instantiateViewController(withIdentifier: "RightMenuNavigationController") as? UISideMenuNavigationController + + // Enable gestures. The left and/or right menus must be set up above for these to work. + // Note that these continue to work on the Navigation Controller independent of the View Controller it displays! + SideMenuManager.menuAddPanGestureToPresent(toView: self.navigationController!.navigationBar) + SideMenuManager.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController!.view) */ open class SideMenuManager : NSObject { @@ -30,7 +30,7 @@ open class SideMenuManager : NSObject { let appWindowRect = UIApplication.shared.keyWindow?.bounds ?? UIWindow().bounds return appWindowRect } - + /** The presentation mode of the menu. @@ -257,7 +257,7 @@ open class SideMenuManager : NSObject { - Parameter toView: The view to add gestures to. - Parameter forMenu: The menu (left or right) you want to add a gesture for. If unspecified, gestures will be added for both sides. - + - Returns: The array of screen edge gestures added to `toView`. */ @discardableResult open class func menuAddScreenEdgePanGesturesToPresent(toView: UIView, forMenu:UIRectEdge? = nil) -> [UIScreenEdgePanGestureRecognizer] { diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index f3a3366..abe088c 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -97,22 +97,22 @@ open class UISideMenuNavigationController: UINavigationController { SideMenuTransition.statusBarView?.isHidden = true coordinator.animate(alongsideTransition: { (context) -> Void in SideMenuTransition.presentMenuStart(forSize: size) - }) { (context) -> Void in - SideMenuTransition.statusBarView?.isHidden = false - } + }) { (context) -> Void in + SideMenuTransition.statusBarView?.isHidden = false + } } override open func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let menuViewController: UINavigationController = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController, let presentingViewController = menuViewController.presentingViewController as? UINavigationController { - presentingViewController.prepare(for: segue, sender: sender) + presentingViewController.prepare(for: segue, sender: sender) } } override open func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { if let menuViewController: UINavigationController = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController, let presentingViewController = menuViewController.presentingViewController as? UINavigationController { - return presentingViewController.shouldPerformSegue(withIdentifier: identifier, sender: sender) + return presentingViewController.shouldPerformSegue(withIdentifier: identifier, sender: sender) } return super.shouldPerformSegue(withIdentifier: identifier, sender: sender) From 142d57e84ce7c2147e5c94f86d4960f333609cbf Mon Sep 17 00:00:00 2001 From: agates4 Date: Thu, 19 Jan 2017 14:25:46 -0500 Subject: [PATCH 03/23] more stupid indentation issues fixed --- Pod/Classes/SideMenuManager.swift | 4 ++-- Pod/Classes/UISideMenuNavigationController.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index 945878f..f186706 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -14,7 +14,7 @@ // Note that these continue to work on the Navigation Controller independent of the View Controller it displays! SideMenuManager.menuAddPanGestureToPresent(toView: self.navigationController!.navigationBar) SideMenuManager.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController!.view) - */ +*/ open class SideMenuManager : NSObject { @@ -257,7 +257,7 @@ open class SideMenuManager : NSObject { - Parameter toView: The view to add gestures to. - Parameter forMenu: The menu (left or right) you want to add a gesture for. If unspecified, gestures will be added for both sides. - + - Returns: The array of screen edge gestures added to `toView`. */ @discardableResult open class func menuAddScreenEdgePanGesturesToPresent(toView: UIView, forMenu:UIRectEdge? = nil) -> [UIScreenEdgePanGestureRecognizer] { diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index abe088c..507a1ca 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -99,7 +99,7 @@ open class UISideMenuNavigationController: UINavigationController { SideMenuTransition.presentMenuStart(forSize: size) }) { (context) -> Void in SideMenuTransition.statusBarView?.isHidden = false - } + } } override open func prepare(for segue: UIStoryboardSegue, sender: Any?) { From 513d9603b2854923c7f5aa764cd8c3bffa3e2b7c Mon Sep 17 00:00:00 2001 From: agates4 Date: Thu, 19 Jan 2017 14:26:25 -0500 Subject: [PATCH 04/23] last indentation fix --- Pod/Classes/UISideMenuNavigationController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index 507a1ca..a3bd9fa 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -125,7 +125,7 @@ open class UISideMenuNavigationController: UINavigationController { super.pushViewController(viewController, animated: animated) return } - + let tabBarController = presentingViewController as? UITabBarController guard let navigationController = (tabBarController?.selectedViewController ?? presentingViewController) as? UINavigationController else { print("SideMenu Warning: attempt to push a View Controller from \(presentingViewController.self) where its navigationController == nil. It must be embedded in a Navigation Controller for this to work.") From 18e1f751e8f1ab6575cf7c33bbc6aac814cd9aa6 Mon Sep 17 00:00:00 2001 From: agates4 Date: Thu, 19 Jan 2017 15:21:30 -0500 Subject: [PATCH 05/23] implemented changed to menuPreserveViewOnPush filter, now instead matching syntax with type(of: ) --- .../UISideMenuNavigationController.swift | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index a3bd9fa..5e74727 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -161,18 +161,19 @@ open class UISideMenuNavigationController: UINavigationController { if SideMenuManager.menuPreserveViewOnPush { var viewControllers = navigationController.viewControllers - let filtered = viewControllers.filter{$0.restorationIdentifier == viewController.restorationIdentifier} - if let preservedView = filtered.first { - viewControllers = viewControllers.filter() { $0 !== preservedView } - viewControllers.append(preservedView) - if SideMenuManager.menuTabMode { - navigationController.setViewControllers(viewControllers, animated: false) + for (index, subViewController) in navigationController.viewControllers.enumerated() { + if type(of: subViewController) == type(of: viewController) { + viewControllers.remove(at: index) + viewControllers.append(subViewController) + if SideMenuManager.menuTabMode { + navigationController.setViewControllers(viewControllers, animated: false) + CATransaction.commit() + return + } + navigationController.setViewControllers(viewControllers, animated: animated) CATransaction.commit() return } - navigationController.setViewControllers(viewControllers, animated: animated) - CATransaction.commit() - return } if SideMenuManager.menuTabMode { navigationController.pushViewController(viewController, animated: false) From 4656a951a2b5a06cf7f0b13bc104b3fb35d88d9e Mon Sep 17 00:00:00 2001 From: agates4 Date: Thu, 19 Jan 2017 16:54:20 -0500 Subject: [PATCH 06/23] removed menuTab option and set default action to always hide SideMenu when transitioning to new view. Refactored menuPreserveViewOnPush to match syntax and efficiency --- Pod/Classes/SideMenuManager.swift | 3 -- .../UISideMenuNavigationController.swift | 37 +++---------------- README.md | 3 -- 3 files changed, 5 insertions(+), 38 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index f186706..b6a52d4 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -45,9 +45,6 @@ open class SideMenuManager : NSObject { /// Retrieves each already created view controller to front when called. Requires class restoration identifiers. Defaults to false. open static var menuPreserveViewOnPush = false - /// Mimics a tab function, by instantly presenting the view controller. Defaults to false. - open static var menuTabMode = false - /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. open static var menuAllowPushOfSameClassTwice = true diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index 5e74727..c3df7b1 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -147,11 +147,6 @@ open class UISideMenuNavigationController: UINavigationController { if SideMenuManager.menuAllowPopIfPossible { for subViewController in navigationController.viewControllers { if type(of: subViewController) == type(of: viewController) { - if SideMenuManager.menuTabMode { - navigationController.popToViewController(subViewController, animated: false) - CATransaction.commit() - return - } navigationController.popToViewController(subViewController, animated: animated) CATransaction.commit() return @@ -161,22 +156,11 @@ open class UISideMenuNavigationController: UINavigationController { if SideMenuManager.menuPreserveViewOnPush { var viewControllers = navigationController.viewControllers - for (index, subViewController) in navigationController.viewControllers.enumerated() { - if type(of: subViewController) == type(of: viewController) { - viewControllers.remove(at: index) - viewControllers.append(subViewController) - if SideMenuManager.menuTabMode { - navigationController.setViewControllers(viewControllers, animated: false) - CATransaction.commit() - return - } - navigationController.setViewControllers(viewControllers, animated: animated) - CATransaction.commit() - return - } - } - if SideMenuManager.menuTabMode { - navigationController.pushViewController(viewController, animated: false) + let filtered = viewControllers.filter {preservedViewController in type(of: preservedViewController) == type(of: viewController)} + if let preservedViewController = filtered.first { + viewControllers = viewControllers.filter() { subController !== preservedViewController } + viewControllers.append(preservedViewController) + navigationController.setViewControllers(viewControllers, animated: animated) CATransaction.commit() return } @@ -189,11 +173,6 @@ open class UISideMenuNavigationController: UINavigationController { var viewControllers = navigationController.viewControllers viewControllers.removeLast() viewControllers.append(viewController) - if SideMenuManager.menuTabMode { - navigationController.setViewControllers(viewControllers, animated: false) - CATransaction.commit() - return - } navigationController.setViewControllers(viewControllers, animated: animated) CATransaction.commit() return @@ -204,12 +183,6 @@ open class UISideMenuNavigationController: UINavigationController { return } - if SideMenuManager.menuTabMode { - navigationController.pushViewController(viewController, animated: false) - CATransaction.commit() - return - } - navigationController.pushViewController(viewController, animated: animated) CATransaction.commit() } diff --git a/README.md b/README.md index f38b96c..6796cb3 100644 --- a/README.md +++ b/README.md @@ -133,9 +133,6 @@ open static var menuPresentMode: MenuPresentMode = .viewSlideOut /// Retrieves each already created view controller to front when called. Requires class restoration identifiers. Defaults to false. open static var menuPreserveViewOnPush = false -/// Mimics a tab function, by instantly presenting the view controller. Defaults to false. -open static var menuTabMode = false - /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. open static var menuAllowPushOfSameClassTwice = true From 5ff4caff44a057f9da5d84953b59471f2998fafb Mon Sep 17 00:00:00 2001 From: agates4 Date: Fri, 20 Jan 2017 13:53:16 -0500 Subject: [PATCH 07/23] When I thought I included the animation in the last commit, I did it in my own test project lol 00ps. Animation default now included as well as disable nav back button. --- Pod/Classes/UISideMenuNavigationController.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index c3df7b1..f90fd0d 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -140,9 +140,12 @@ open class UISideMenuNavigationController: UINavigationController { self.visibleViewController?.viewWillAppear(false) // Hack: force selection to get cleared on UITableViewControllers when reappearing using custom transitions }) + let areAnimationsEnabled = UIView.areAnimationsEnabled + UIView.setAnimationsEnabled(true) UIView.animate(withDuration: SideMenuManager.menuAnimationDismissDuration, animations: { () -> Void in SideMenuTransition.hideMenuStart() }) + UIView.setAnimationsEnabled(areAnimationsEnabled) if SideMenuManager.menuAllowPopIfPossible { for subViewController in navigationController.viewControllers { @@ -156,9 +159,10 @@ open class UISideMenuNavigationController: UINavigationController { if SideMenuManager.menuPreserveViewOnPush { var viewControllers = navigationController.viewControllers - let filtered = viewControllers.filter {preservedViewController in type(of: preservedViewController) == type(of: viewController)} + let filtered = viewControllers.filter { preservedViewController in type(of: preservedViewController) == type(of: viewController) } if let preservedViewController = filtered.first { - viewControllers = viewControllers.filter() { subController !== preservedViewController } + viewControllers = viewControllers.filter { subViewController in subViewController !== preservedViewController } + preservedViewController.navigationItem.hidesBackButton = true viewControllers.append(preservedViewController) navigationController.setViewControllers(viewControllers, animated: animated) CATransaction.commit() From 93dacf7b1df7fd7bb82ecafb23df54f33efee46c Mon Sep 17 00:00:00 2001 From: agates4 Date: Fri, 20 Jan 2017 13:54:47 -0500 Subject: [PATCH 08/23] Default for "PreserveViewOnPush" is now to always disable the back button. --- Pod/Classes/UISideMenuNavigationController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index f90fd0d..f3e9b68 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -168,6 +168,7 @@ open class UISideMenuNavigationController: UINavigationController { CATransaction.commit() return } + viewController.navigationItem.hidesBackButton = true navigationController.pushViewController(viewController, animated: animated) CATransaction.commit() return From c3a50dac9b40b3d3b648e1733a517423de0f509e Mon Sep 17 00:00:00 2001 From: agates4 Date: Fri, 20 Jan 2017 13:57:02 -0500 Subject: [PATCH 09/23] updated documentation (disables back button) --- Pod/Classes/SideMenuManager.swift | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index b6a52d4..0abccc6 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -42,7 +42,7 @@ open class SideMenuManager : NSObject { */ open static var menuPresentMode: MenuPresentMode = .viewSlideOut - /// Retrieves each already created view controller to front when called. Requires class restoration identifiers. Defaults to false. + /// Retrieves each already created view controller to front when called. Disables navigation back button. Defaults to false. open static var menuPreserveViewOnPush = false /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. diff --git a/README.md b/README.md index 6796cb3..6f5ba69 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ There are four modes in MenuPresentMode: */ open static var menuPresentMode: MenuPresentMode = .viewSlideOut -/// Retrieves each already created view controller to front when called. Requires class restoration identifiers. Defaults to false. +/// Retrieves each already created view controller to front when called. Disables navigation back button. Defaults to false. open static var menuPreserveViewOnPush = false /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. From 72d998b1848494c6d7a2ac63db2a2d5ac2de082b Mon Sep 17 00:00:00 2001 From: agates4 Date: Fri, 20 Jan 2017 18:40:46 -0500 Subject: [PATCH 10/23] Enum changed / new "hide back button" behaviors --- Pod/Classes/SideMenuManager.swift | 61 ++++++++++++++++--- .../UISideMenuNavigationController.swift | 42 ++++++++----- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index 0abccc6..d4f231c 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -18,6 +18,14 @@ open class SideMenuManager : NSObject { + @objc public enum MenuPushBehavior : Int { + case defaultBehavior + case popWhenPossible + case replace + case preserve + case preserveAndHideBackButton + } + @objc public enum MenuPresentMode : Int { case menuSlideIn case viewSlideOut @@ -31,6 +39,18 @@ open class SideMenuManager : NSObject { return appWindowRect } + /** + The push behavior of the menu. + + There are six modes in MenuPushBehavior: + - defaultBehavior: The view controller is simply pushed into the stack. + - popWhenPossible: Pops to any view controller already in the navigation stack instead of the view controller being pushed if they share the same class. + - preserve: Retrieves each already created view controller to front when called. + - preserveAndHideBackButton: Retrieves each already created view controller to front when called, and hides the back button. + - replace: Releases the current view controller and pushes the new view controller. + */ + open static var menuPushBehavior: MenuPushBehavior = .defaultBehavior + /** The presentation mode of the menu. @@ -41,16 +61,10 @@ open class SideMenuManager : NSObject { - menuDissolveIn: The menu dissolves in over the existing view controller. */ open static var menuPresentMode: MenuPresentMode = .viewSlideOut - - /// Retrieves each already created view controller to front when called. Disables navigation back button. Defaults to false. - open static var menuPreserveViewOnPush = false - + /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. open static var menuAllowPushOfSameClassTwice = true - /// Pops to any view controller already in the navigation stack instead of the view controller being pushed if they share the same class. Defaults to false. - open static var menuAllowPopIfPossible = false - /// Width of the menu when presented on screen, showing the existing view controller in the remaining space. Default is 75% of the screen width. open static var menuWidth: CGFloat = max(round(min((appScreenRect.width), (appScreenRect.height)) * 0.75), 240) @@ -96,8 +110,37 @@ open class SideMenuManager : NSObject { /// When true, pushViewController called within the menu it will push the new view controller inside of the menu. Otherwise, it is pushed on the menu's presentingViewController. Default is false. open static var menuAllowSubmenus: Bool = false - /// When true, pushViewController will replace the last view controller in the navigation controller's viewController stack instead of appending to it. This makes menus similar to tab bar controller behavior. - open static var menuReplaceOnPush: Bool = false + /// -Warning: Deprecated. Use `menuPushBehavior = .popWhenPossible` instead. + @available(*, deprecated, renamed: "menuPushBehavior", message: "Use `menuPushBehavior = .popWhenPossible` instead.") + open static var menuAllowPopIfPossible: Bool { + get { + if menuPushBehavior == .popWhenPossible { + return true + } + return false + } + set { + if newValue { + menuPushBehavior = .popWhenPossible + } + } + } + + /// -Warning: Deprecated. Use `menuPushBehavior = .replace` instead. + @available(*, deprecated, renamed: "menuPushBehavior", message: "Use `menuPushBehavior = .replace` instead.") + open static var menuReplaceOnPush: Bool { + get { + if menuPushBehavior == .replace { + return true + } + return false + } + set { + if newValue { + menuPushBehavior = .replace + } + } + } /// -Warning: Deprecated. Use `menuAnimationTransformScaleFactor` instead. @available(*, deprecated, renamed: "menuAnimationTransformScaleFactor") diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index f3e9b68..2ab974d 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -147,7 +147,17 @@ open class UISideMenuNavigationController: UINavigationController { }) UIView.setAnimationsEnabled(areAnimationsEnabled) - if SideMenuManager.menuAllowPopIfPossible { + if let lastViewController = navigationController.viewControllers.last, !SideMenuManager.menuAllowPushOfSameClassTwice && type(of: lastViewController) == type(of: viewController) { + CATransaction.commit() + return + } + + switch SideMenuManager.menuPushBehavior { + case .defaultBehavior: + navigationController.pushViewController(viewController, animated: animated) + CATransaction.commit() + return + case .popWhenPossible: for subViewController in navigationController.viewControllers { if type(of: subViewController) == type(of: viewController) { navigationController.popToViewController(subViewController, animated: animated) @@ -155,9 +165,20 @@ open class UISideMenuNavigationController: UINavigationController { return } } - } - - if SideMenuManager.menuPreserveViewOnPush { + case .preserve: + var viewControllers = navigationController.viewControllers + let filtered = viewControllers.filter { preservedViewController in type(of: preservedViewController) == type(of: viewController) } + if let preservedViewController = filtered.first { + viewControllers = viewControllers.filter { subViewController in subViewController !== preservedViewController } + viewControllers.append(preservedViewController) + navigationController.setViewControllers(viewControllers, animated: animated) + CATransaction.commit() + return + } + navigationController.pushViewController(viewController, animated: animated) + CATransaction.commit() + return + case .preserveAndHideBackButton: var viewControllers = navigationController.viewControllers let filtered = viewControllers.filter { preservedViewController in type(of: preservedViewController) == type(of: viewController) } if let preservedViewController = filtered.first { @@ -172,24 +193,15 @@ open class UISideMenuNavigationController: UINavigationController { navigationController.pushViewController(viewController, animated: animated) CATransaction.commit() return - } - - if SideMenuManager.menuReplaceOnPush { + case .replace: var viewControllers = navigationController.viewControllers viewControllers.removeLast() + viewController.navigationItem.hidesBackButton = true viewControllers.append(viewController) navigationController.setViewControllers(viewControllers, animated: animated) CATransaction.commit() return } - - if let lastViewController = navigationController.viewControllers.last, !SideMenuManager.menuAllowPushOfSameClassTwice && type(of: lastViewController) == type(of: viewController) { - CATransaction.commit() - return - } - - navigationController.pushViewController(viewController, animated: animated) - CATransaction.commit() } } From 52960fac95902f2bd323f4cd88755cbc80b72123 Mon Sep 17 00:00:00 2001 From: agates4 Date: Fri, 20 Jan 2017 18:50:04 -0500 Subject: [PATCH 11/23] updated readme and fixed indentation issues --- Pod/Classes/SideMenuManager.swift | 2 +- README.md | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index d4f231c..15c1d28 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -61,7 +61,7 @@ open class SideMenuManager : NSObject { - menuDissolveIn: The menu dissolves in over the existing view controller. */ open static var menuPresentMode: MenuPresentMode = .viewSlideOut - + /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. open static var menuAllowPushOfSameClassTwice = true diff --git a/README.md b/README.md index 6f5ba69..cf7faa9 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,18 @@ That's it. ### Customization Just type `SideMenuManager.menu...` and code completion will show you everything you can customize (defaults are shown below for reference): ``` swift +/** +The push behavior of the menu. + +There are six modes in MenuPushBehavior: +- defaultBehavior: The view controller is simply pushed into the stack. +- popWhenPossible: Pops to any view controller already in the navigation stack instead of the view controller being pushed if they share the same class. +- preserve: Retrieves each already created view controller to front when called. +- preserveAndHideBackButton: Retrieves each already created view controller to front when called, and hides the back button. +- replace: Releases the current view controller and pushes the new view controller. +*/ +open static var menuPushBehavior: MenuPushBehavior = .defaultBehavior + /** The presentation mode of the menu. @@ -130,15 +142,9 @@ There are four modes in MenuPresentMode: */ open static var menuPresentMode: MenuPresentMode = .viewSlideOut -/// Retrieves each already created view controller to front when called. Disables navigation back button. Defaults to false. -open static var menuPreserveViewOnPush = false - /// Prevents the same view controller (or a view controller of the same class) from being pushed more than once. Defaults to true. open static var menuAllowPushOfSameClassTwice = true -/// Pops to any view controller already in the navigation stack instead of the view controller being pushed if they share the same class. Defaults to false. -open static var menuAllowPopIfPossible = false - /// Width of the menu when presented on screen, showing the existing view controller in the remaining space. Default is 75% of the screen width. open static var menuWidth: CGFloat = max(round(min((appScreenRect.width), (appScreenRect.height)) * 0.75), 240) @@ -187,9 +193,6 @@ open static var menuFadeStatusBar = true /// When true, pushViewController called within the menu it will push the new view controller inside of the menu. Otherwise, it is pushed on the menu's presentingViewController. Default is false. open static var menuAllowSubmenus: Bool = false -/// When true, pushViewController will replace the last view controller in the navigation controller's viewController stack instead of appending to it. This makes menus similar to tab bar controller behavior. -open static var menuReplaceOnPush: Bool = false - /** The blur effect style of the menu if the menu's root view controller is a UITableViewController or UICollectionViewController. From b37bae8a02f0b6b4af3e73fd950eaf1093a2eef8 Mon Sep 17 00:00:00 2001 From: agates4 Date: Fri, 20 Jan 2017 18:52:20 -0500 Subject: [PATCH 12/23] deprecation function simplification for .replace and .popifpossible --- Pod/Classes/SideMenuManager.swift | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index 15c1d28..e349cb9 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -114,10 +114,7 @@ open class SideMenuManager : NSObject { @available(*, deprecated, renamed: "menuPushBehavior", message: "Use `menuPushBehavior = .popWhenPossible` instead.") open static var menuAllowPopIfPossible: Bool { get { - if menuPushBehavior == .popWhenPossible { - return true - } - return false + return menuPushBehavior == .popWhenPossible } set { if newValue { @@ -130,10 +127,7 @@ open class SideMenuManager : NSObject { @available(*, deprecated, renamed: "menuPushBehavior", message: "Use `menuPushBehavior = .replace` instead.") open static var menuReplaceOnPush: Bool { get { - if menuPushBehavior == .replace { - return true - } - return false + return menuPushBehavior == .replace } set { if newValue { From 08145abacbe5bf085480f8fac338a3838030e598 Mon Sep 17 00:00:00 2001 From: agates4 Date: Fri, 20 Jan 2017 18:59:38 -0500 Subject: [PATCH 13/23] Documentation - added note about .replace hiding the back button. --- Pod/Classes/SideMenuManager.swift | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index e349cb9..169f8a7 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -47,7 +47,7 @@ open class SideMenuManager : NSObject { - popWhenPossible: Pops to any view controller already in the navigation stack instead of the view controller being pushed if they share the same class. - preserve: Retrieves each already created view controller to front when called. - preserveAndHideBackButton: Retrieves each already created view controller to front when called, and hides the back button. - - replace: Releases the current view controller and pushes the new view controller. + - replace: Releases the current view controller and pushes the new view controller. Hides the back button by default. */ open static var menuPushBehavior: MenuPushBehavior = .defaultBehavior diff --git a/README.md b/README.md index cf7faa9..8f28332 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ There are six modes in MenuPushBehavior: - popWhenPossible: Pops to any view controller already in the navigation stack instead of the view controller being pushed if they share the same class. - preserve: Retrieves each already created view controller to front when called. - preserveAndHideBackButton: Retrieves each already created view controller to front when called, and hides the back button. -- replace: Releases the current view controller and pushes the new view controller. +- replace: Releases the current view controller and pushes the new view controller. Hides the back button by default. */ open static var menuPushBehavior: MenuPushBehavior = .defaultBehavior From fbb692cd614c8b52b4a4ffc707c42140a6614737 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:14:55 -0800 Subject: [PATCH 14/23] Some refactoring and added in .subMenu to the list of behaviors. --- Pod/Classes/SideMenuManager.swift | 71 +++++++++++-------- .../UISideMenuNavigationController.swift | 42 ++++------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index 169f8a7..dd7c11d 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -18,19 +18,20 @@ open class SideMenuManager : NSObject { - @objc public enum MenuPushBehavior : Int { - case defaultBehavior - case popWhenPossible - case replace - case preserve - case preserveAndHideBackButton + @objc public enum MenuPushStyle : Int { + case defaultBehavior, + popWhenPossible, + replace, + preserve, + preserveAndHideBackButton, + subMenu } @objc public enum MenuPresentMode : Int { - case menuSlideIn - case viewSlideOut - case viewSlideInOut - case menuDissolveIn + case menuSlideIn, + viewSlideOut, + viewSlideInOut, + menuDissolveIn } // Bounds which has been allocated for the app on the whole device screen @@ -42,14 +43,15 @@ open class SideMenuManager : NSObject { /** The push behavior of the menu. - There are six modes in MenuPushBehavior: - - defaultBehavior: The view controller is simply pushed into the stack. - - popWhenPossible: Pops to any view controller already in the navigation stack instead of the view controller being pushed if they share the same class. - - preserve: Retrieves each already created view controller to front when called. - - preserveAndHideBackButton: Retrieves each already created view controller to front when called, and hides the back button. - - replace: Releases the current view controller and pushes the new view controller. Hides the back button by default. + There are six modes in MenuPushStyle: + - defaultBehavior: The view controller is pushed onto the stack. + - popWhenPossible: If a view controller already in the stack is of the same class as the pushed view controller, the stack is instead popped back to the existing view controller. This behavior can help users from getting lost in a deep navigation stack. + - preserve: If a view controller already in the stack is of the same class as the pushed view controller, the existing view controller is pushed to the end of the stack. This behavior is similar to a UITabBarController. + - preserveAndHideBackButton: Same as .preserve and back buttons are automatically hidden. + - replace: Any existing view controllers are released from the stack and replaced with the pushed view controller. Back buttons are automatically hidden. This behavior is ideal if view controllers require a lot of memory or their state doesn't need to be preserved.. + - subMenu: Unlike all other behaviors that push using the menu's presentingViewController, this behavior pushes view controllers within the menu. Use this behavior if you want to display a sub menu. */ - open static var menuPushBehavior: MenuPushBehavior = .defaultBehavior + open static var menuPushStyle: MenuPushStyle = .defaultBehavior /** The presentation mode of the menu. @@ -107,31 +109,42 @@ open class SideMenuManager : NSObject { /// Draws the `menuAnimationBackgroundColor` behind the status bar. Default is true. open static var menuFadeStatusBar = true - /// When true, pushViewController called within the menu it will push the new view controller inside of the menu. Otherwise, it is pushed on the menu's presentingViewController. Default is false. - open static var menuAllowSubmenus: Bool = false - /// -Warning: Deprecated. Use `menuPushBehavior = .popWhenPossible` instead. - @available(*, deprecated, renamed: "menuPushBehavior", message: "Use `menuPushBehavior = .popWhenPossible` instead.") - open static var menuAllowPopIfPossible: Bool { + /// -Warning: Deprecated. Use `menuPushStyle = .subMenu` instead. + @available(*, deprecated, renamed: "menuPushStyle", message: "Use `menuPushStyle = .subMenu` instead.") + open static var menuAllowSubmenus: Bool { get { - return menuPushBehavior == .popWhenPossible + return menuPushStyle == .subMenu } set { if newValue { - menuPushBehavior = .popWhenPossible + menuPushStyle = .subMenu } } } - /// -Warning: Deprecated. Use `menuPushBehavior = .replace` instead. - @available(*, deprecated, renamed: "menuPushBehavior", message: "Use `menuPushBehavior = .replace` instead.") - open static var menuReplaceOnPush: Bool { + /// -Warning: Deprecated. Use `menuPushStyle = .popWhenPossible` instead. + @available(*, deprecated, renamed: "menuPushStyle", message: "Use `menuPushStyle = .popWhenPossible` instead.") + open static var menuAllowPopIfPossible: Bool { get { - return menuPushBehavior == .replace + return menuPushStyle == .popWhenPossible } set { if newValue { - menuPushBehavior = .replace + menuPushStyle = .popWhenPossible + } + } + } + + /// -Warning: Deprecated. Use `menuPushStyle = .replace` instead. + @available(*, deprecated, renamed: "menuPushStyle", message: "Use `menuPushStyle = .replace` instead.") + open static var menuReplaceOnPush: Bool { + get { + return menuPushStyle == .replace + } + set { + if newValue { + menuPushStyle = .replace } } } diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index 2ab974d..78396f8 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -119,7 +119,7 @@ open class UISideMenuNavigationController: UINavigationController { } override open func pushViewController(_ viewController: UIViewController, animated: Bool) { - guard viewControllers.count > 0 && !SideMenuManager.menuAllowSubmenus else { + guard viewControllers.count > 0 && SideMenuManager.menuPushStyle != .subMenu else { // NOTE: pushViewController is called by init(rootViewController: UIViewController) // so we must perform the normal super method in this case. super.pushViewController(viewController, animated: animated) @@ -152,56 +152,42 @@ open class UISideMenuNavigationController: UINavigationController { return } - switch SideMenuManager.menuPushBehavior { - case .defaultBehavior: - navigationController.pushViewController(viewController, animated: animated) - CATransaction.commit() - return + switch SideMenuManager.menuPushStyle { + case .subMenu, .defaultBehavior: break // .subMenu handled earlier, .defaultBehavior falls through to end case .popWhenPossible: - for subViewController in navigationController.viewControllers { + for subViewController in navigationController.viewControllers.reversed() { if type(of: subViewController) == type(of: viewController) { navigationController.popToViewController(subViewController, animated: animated) CATransaction.commit() return } } - case .preserve: + case .preserve, .preserveAndHideBackButton: var viewControllers = navigationController.viewControllers let filtered = viewControllers.filter { preservedViewController in type(of: preservedViewController) == type(of: viewController) } - if let preservedViewController = filtered.first { - viewControllers = viewControllers.filter { subViewController in subViewController !== preservedViewController } - viewControllers.append(preservedViewController) - navigationController.setViewControllers(viewControllers, animated: animated) - CATransaction.commit() - return - } - navigationController.pushViewController(viewController, animated: animated) - CATransaction.commit() - return - case .preserveAndHideBackButton: - var viewControllers = navigationController.viewControllers - let filtered = viewControllers.filter { preservedViewController in type(of: preservedViewController) == type(of: viewController) } - if let preservedViewController = filtered.first { + if let preservedViewController = filtered.last { viewControllers = viewControllers.filter { subViewController in subViewController !== preservedViewController } + if SideMenuManager.menuPushStyle == .preserveAndHideBackButton { preservedViewController.navigationItem.hidesBackButton = true + } viewControllers.append(preservedViewController) navigationController.setViewControllers(viewControllers, animated: animated) CATransaction.commit() return } + if SideMenuManager.menuPushStyle == .preserveAndHideBackButton { viewController.navigationItem.hidesBackButton = true - navigationController.pushViewController(viewController, animated: animated) - CATransaction.commit() - return + } case .replace: var viewControllers = navigationController.viewControllers - viewControllers.removeLast() viewController.navigationItem.hidesBackButton = true - viewControllers.append(viewController) - navigationController.setViewControllers(viewControllers, animated: animated) + navigationController.setViewControllers([viewController], animated: animated) CATransaction.commit() return } + + navigationController.pushViewController(viewController, animated: animated) + CATransaction.commit() } } From 63e0b2b11b5ddc900a535998d50c9ffc170efb10 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:17:52 -0800 Subject: [PATCH 15/23] New properties for further customizing non-interactive menu animations. --- Pod/Classes/SideMenuManager.swift | 15 ++++++++++-- Pod/Classes/SideMenuTransition.swift | 35 ++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index dd7c11d..48d7c85 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -71,10 +71,13 @@ open class SideMenuManager : NSObject { open static var menuWidth: CGFloat = max(round(min((appScreenRect.width), (appScreenRect.height)) * 0.75), 240) /// Duration of the animation when the menu is presented without gestures. Default is 0.35 seconds. - open static var menuAnimationPresentDuration = 0.35 + open static var menuAnimationPresentDuration: Double = 0.35 /// Duration of the animation when the menu is dismissed without gestures. Default is 0.35 seconds. - open static var menuAnimationDismissDuration = 0.35 + open static var menuAnimationDismissDuration: Double = 0.35 + + /// Duration of the remaining animation when the menu is partially dismissed with gestures. Default is 0.2 seconds. + open static var menuAnimationCompleteGestureDuration: Double = 0.20 /// Amount to fade the existing view controller when the menu is presented. Default is 0 for no fade. Set to 1 to fade completely. open static var menuAnimationFadeStrength: CGFloat = 0 @@ -109,6 +112,14 @@ open class SideMenuManager : NSObject { /// Draws the `menuAnimationBackgroundColor` behind the status bar. Default is true. open static var menuFadeStatusBar = true + /// The animation options when a menu is displayed. Ignored when displayed with a gesture. + open static var menuAnimationOptions: UIViewAnimationOptions = .curveEaseInOut + + /// The animation spring damping when a menu is displayed. Ignored when displayed with a gesture. + open static var menuAnimationUsingSpringWithDamping: CGFloat = 1 + + /// The animation initial spring velocity when a menu is displayed. Ignored when displayed with a gesture. + open static var menuAnimationInitialSpringVelocity: CGFloat = 1 /// -Warning: Deprecated. Use `menuPushStyle = .subMenu` instead. @available(*, deprecated, renamed: "menuPushStyle", message: "Use `menuPushStyle = .subMenu` instead.") diff --git a/Pod/Classes/SideMenuTransition.swift b/Pod/Classes/SideMenuTransition.swift index 0c3801a..b1f932a 100644 --- a/Pod/Classes/SideMenuTransition.swift +++ b/Pod/Classes/SideMenuTransition.swift @@ -362,17 +362,15 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr SideMenuTransition.hideMenuStart() } - // perform the animation! - let duration = transitionDuration(using: transitionContext) - let options: UIViewAnimationOptions = interactive ? .curveLinear : UIViewAnimationOptions() - UIView.animate(withDuration: duration, delay: 0, options: options, animations: { () -> Void in + let animate = { if self.presenting { SideMenuTransition.presentMenuStart() } else { SideMenuTransition.hideMenuStart() } - }) { (finished) -> Void in + } + let complete = { container.isUserInteractionEnabled = true // tell our transitionContext object that we've finished animating @@ -421,10 +419,37 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr transitionContext.completeTransition(true) menuView.removeFromSuperview() } + + // perform the animation! + let duration = transitionDuration(using: transitionContext) + if interactive { + UIView.animate(withDuration: duration, + delay: 0, + options: .curveLinear, + animations: { + animate() + }, completion: { (finished) in + complete() + }) + } else { + UIView.animate(withDuration: duration, + delay: 0, + usingSpringWithDamping: SideMenuManager.menuAnimationUsingSpringWithDamping, + initialSpringVelocity: SideMenuManager.menuAnimationInitialSpringVelocity, + options: SideMenuManager.menuAnimationOptions, + animations: { + animate() + }) { (finished) -> Void in + complete() + } + } } // return how many seconds the transiton animation will take open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + if interactive { + return SideMenuManager.menuAnimationCompleteGestureDuration + } return presenting ? SideMenuManager.menuAnimationPresentDuration : SideMenuManager.menuAnimationDismissDuration } From 8fbf4002ac608ddce38ccfde689ea3db6e72cda9 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:19:26 -0800 Subject: [PATCH 16/23] Tighter logic for responding to only a single gesture to avoid conflicts. --- Pod/Classes/SideMenuTransition.swift | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Pod/Classes/SideMenuTransition.swift b/Pod/Classes/SideMenuTransition.swift index b1f932a..18613a4 100644 --- a/Pod/Classes/SideMenuTransition.swift +++ b/Pod/Classes/SideMenuTransition.swift @@ -13,6 +13,7 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr fileprivate var presenting = false fileprivate var interactive = false fileprivate static weak var originalSuperview: UIView? + fileprivate static weak var activeGesture: UIGestureRecognizer? fileprivate static var switchMenus = false internal static let singleton = SideMenuTransition() @@ -85,6 +86,14 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr } internal class func handlePresentMenuPan(_ pan: UIPanGestureRecognizer) { + if activeGesture == nil { + activeGesture = pan + } else if pan != activeGesture { + pan.isEnabled = false + pan.isEnabled = true + return + } + // how much distance have we panned in reference to the parent view? guard let view = viewControllerForPresentedMenu != nil ? viewControllerForPresentedMenu?.view : pan.view else { return @@ -109,6 +118,8 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr let visibleViewController = visibleViewController { singleton.interactive = true visibleViewController.present(menuViewController, animated: true, completion: nil) + } else { + return } } @@ -141,13 +152,23 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr singleton.update(0.9999) } singleton.finish() + activeGesture = nil } else { singleton.cancel() + activeGesture = nil } } } internal class func handleHideMenuPan(_ pan: UIPanGestureRecognizer) { + if activeGesture == nil { + activeGesture = pan + } else if pan != activeGesture { + pan.isEnabled = false + pan.isEnabled = true + return + } + let translation = pan.translation(in: pan.view!) let direction:CGFloat = SideMenuTransition.presentDirection == .left ? -1 : 1 let distance = translation.x / SideMenuManager.menuWidth * direction @@ -168,8 +189,10 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr singleton.update(0.9999) } singleton.finish() + activeGesture = nil } else { singleton.cancel() + activeGesture = nil } } } From 192ef476bd9771b9c780c36151b803c6ae2084ff Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:19:59 -0800 Subject: [PATCH 17/23] Refactoring. --- Pod/Classes/SideMenuTransition.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Pod/Classes/SideMenuTransition.swift b/Pod/Classes/SideMenuTransition.swift index 18613a4..0b5839e 100644 --- a/Pod/Classes/SideMenuTransition.swift +++ b/Pod/Classes/SideMenuTransition.swift @@ -8,7 +8,7 @@ import UIKit -open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate { +open class SideMenuTransition: UIPercentDrivenInteractiveTransition { fileprivate var presenting = false fileprivate var interactive = false @@ -337,7 +337,9 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr } } - // MARK: UIViewControllerAnimatedTransitioning protocol methods +} + +extension SideMenuTransition: UIViewControllerAnimatedTransitioning { // animate a change from one viewcontroller to another open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { @@ -392,7 +394,7 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr SideMenuTransition.hideMenuStart() } } - + let complete = { container.isUserInteractionEnabled = true @@ -476,7 +478,9 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr return presenting ? SideMenuManager.menuAnimationPresentDuration : SideMenuManager.menuAnimationDismissDuration } - // MARK: UIViewControllerTransitioningDelegate protocol methods +} + +extension SideMenuTransition: UIViewControllerTransitioningDelegate { // return the animator when presenting a viewcontroller // rememeber that an animator (or animation controller) is any object that aheres to the UIViewControllerAnimatedTransitioning protocol From 8f26bbb2d9eabe8843ac03b2558eb78c05a73491 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:20:27 -0800 Subject: [PATCH 18/23] Additional debug warnings to help troubleshoot common problems. --- Pod/Classes/SideMenuManager.swift | 12 ++++++++++++ Pod/Classes/UISideMenuNavigationController.swift | 10 +++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index 48d7c85..b805bf5 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -328,6 +328,10 @@ open class SideMenuManager : NSObject { leftScreenEdgeGestureRecognizer.cancelsTouchesInView = true toView.addGestureRecognizer(leftScreenEdgeGestureRecognizer) array.append(leftScreenEdgeGestureRecognizer) + + if SideMenuManager.menuLeftNavigationController == nil { + print("SideMenu Warning: menuAddScreenEdgePanGesturesToPresent for the left side was called before menuLeftNavigationController has been defined. The gesture will not work without a menu.") + } } if forMenu != .left { @@ -337,6 +341,10 @@ open class SideMenuManager : NSObject { rightScreenEdgeGestureRecognizer.cancelsTouchesInView = true toView.addGestureRecognizer(rightScreenEdgeGestureRecognizer) array.append(rightScreenEdgeGestureRecognizer) + + if SideMenuManager.menuRightNavigationController == nil { + print("SideMenu Warning: menuAddScreenEdgePanGesturesToPresent for the right side was called before menuRightNavigationController has been defined. The gesture will not work without a menu.") + } } return array @@ -354,6 +362,10 @@ open class SideMenuManager : NSObject { panGestureRecognizer.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handlePresentMenuPan(_:))) toView.addGestureRecognizer(panGestureRecognizer) + if SideMenuManager.menuLeftNavigationController ?? SideMenuManager.menuRightNavigationController == nil { + print("SideMenu Warning: menuAddPanGestureToPresent called before menuLeftNavigationController or menuRightNavigationController have been defined. Gestures will not work without a menu.") + } + return panGestureRecognizer } } diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index 78396f8..89fbbb1 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -21,7 +21,7 @@ open class UISideMenuNavigationController: UINavigationController { } /// Whether the menu appears on the right or left side of the screen. Right is the default. - @IBInspectable open var leftSide:Bool = false { + @IBInspectable open var leftSide: Bool = false { didSet { if isViewLoaded && oldValue != leftSide { // suppress warnings didSetSide() @@ -53,6 +53,10 @@ open class UISideMenuNavigationController: UINavigationController { self.view.isHidden = false }) } + + if topViewController == nil { + print("SideMenu Warning: the menu doesn't have a view controller to show! UISideMenuNavigationController needs a view controller to display just like a UINavigationController.") + } } override open func viewWillDisappear(_ animated: Bool) { @@ -168,7 +172,7 @@ open class UISideMenuNavigationController: UINavigationController { if let preservedViewController = filtered.last { viewControllers = viewControllers.filter { subViewController in subViewController !== preservedViewController } if SideMenuManager.menuPushStyle == .preserveAndHideBackButton { - preservedViewController.navigationItem.hidesBackButton = true + preservedViewController.navigationItem.hidesBackButton = true } viewControllers.append(preservedViewController) navigationController.setViewControllers(viewControllers, animated: animated) @@ -176,7 +180,7 @@ open class UISideMenuNavigationController: UINavigationController { return } if SideMenuManager.menuPushStyle == .preserveAndHideBackButton { - viewController.navigationItem.hidesBackButton = true + viewController.navigationItem.hidesBackButton = true } case .replace: var viewControllers = navigationController.viewControllers From 743deb7e037c052f0509585ae67e28b1993b39c5 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:23:58 -0800 Subject: [PATCH 19/23] Update comment. --- Pod/Classes/SideMenuManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index b805bf5..3059a15 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -41,7 +41,7 @@ open class SideMenuManager : NSObject { } /** - The push behavior of the menu. + The push style of the menu. There are six modes in MenuPushStyle: - defaultBehavior: The view controller is pushed onto the stack. From 60157eb0011061ffc1f37bfcfad9b74d4b4909d5 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:24:50 -0800 Subject: [PATCH 20/23] Updated README. --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 464ba6e..991a09d 100644 --- a/README.md +++ b/README.md @@ -127,16 +127,17 @@ That's it. Just type `SideMenuManager.menu...` and code completion will show you everything you can customize (defaults are shown below for reference): ``` swift /** -The push behavior of the menu. +The push style of the menu. -There are six modes in MenuPushBehavior: -- defaultBehavior: The view controller is simply pushed into the stack. -- popWhenPossible: Pops to any view controller already in the navigation stack instead of the view controller being pushed if they share the same class. -- preserve: Retrieves each already created view controller to front when called. -- preserveAndHideBackButton: Retrieves each already created view controller to front when called, and hides the back button. -- replace: Releases the current view controller and pushes the new view controller. Hides the back button by default. +There are six modes in MenuPushStyle: +- defaultBehavior: The view controller is pushed onto the stack. +- popWhenPossible: If a view controller already in the stack is of the same class as the pushed view controller, the stack is instead popped back to the existing view controller. This behavior can help users from getting lost in a deep navigation stack. +- preserve: If a view controller already in the stack is of the same class as the pushed view controller, the existing view controller is pushed to the end of the stack. This behavior is similar to a UITabBarController. +- preserveAndHideBackButton: Same as .preserve and back buttons are automatically hidden. +- replace: Any existing view controllers are released from the stack and replaced with the pushed view controller. Back buttons are automatically hidden. This behavior is ideal if view controllers require a lot of memory or their state doesn't need to be preserved.. +- subMenu: Unlike all other behaviors that push using the menu's presentingViewController, this behavior pushes view controllers within the menu. Use this behavior if you want to display a sub menu. */ -open static var menuPushBehavior: MenuPushBehavior = .defaultBehavior +open static var menuPushStyle: MenuPushStyle = .defaultBehavior /** The presentation mode of the menu. @@ -197,8 +198,14 @@ open static var menuParallaxStrength: Int = 0 /// Draws the `menuAnimationBackgroundColor` behind the status bar. Default is true. open static var menuFadeStatusBar = true -/// When true, pushViewController called within the menu it will push the new view controller inside of the menu. Otherwise, it is pushed on the menu's presentingViewController. Default is false. -open static var menuAllowSubmenus: Bool = false +/// The animation options when a menu is displayed. Ignored when displayed with a gesture. +open static var menuAnimationOptions: UIViewAnimationOptions = .curveEaseInOut + +/// The animation spring damping when a menu is displayed. Ignored when displayed with a gesture. +open static var menuAnimationUsingSpringWithDamping: CGFloat = 1 + +/// The animation initial spring velocity when a menu is displayed. Ignored when displayed with a gesture. +open static var menuAnimationInitialSpringVelocity: CGFloat = 1 /** The blur effect style of the menu if the menu's root view controller is a UITableViewController or UICollectionViewController. From 4ed14e785653ac186ffddd7239328c5dfbf2d423 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:25:07 -0800 Subject: [PATCH 21/23] Update podspec. --- SideMenu.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SideMenu.podspec b/SideMenu.podspec index 0134fea..9897e1f 100644 --- a/SideMenu.podspec +++ b/SideMenu.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = "SideMenu" - s.version = "2.1.5" + s.version = "2.2.0" s.summary = "Simple side menu control for iOS in Swift inspired by Facebook. Right and Left sides. No coding required." # This description is used to generate tags and improve search results. From bac8e1591d447b14c6d539921d4ee8d481aa391e Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:27:31 -0800 Subject: [PATCH 22/23] Update README for Cocoapods. --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 991a09d..c946912 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![License](https://img.shields.io/cocoapods/l/SideMenu.svg?style=flat)](http://cocoapods.org/pods/SideMenu) [![Platform](https://img.shields.io/cocoapods/p/SideMenu.svg?style=flat)](http://cocoapods.org/pods/SideMenu) -### If you like SideMenu, give it a ★ at the top right of this page. +### If you like SideMenu, give it a ★ at the top right of its [GitHub](https://github.com/jonkykong/SideMenu) page. #### Using SideMenu in your app? [Send](mailto:contact@jonkent.me?subject=SideMenu in action!) me a link to your app in the app store! > I'm Jon Kent and I freelance iOS design, development, and mobile strategies. I love coffee and play the drums. [**Hire me**](mailto:contact@jonkent.me?subject=Let's build something amazing.) to help you make cool stuff. I also have a [website](http://jonkent.me). *Note: If you're having a problem with SideMenu, please open an [issue](https://github.com/jonkykong/SideMenu/issues/new) and do not email me.* @@ -12,12 +12,12 @@ ## Overview SideMenu is a simple and versatile side menu control written in Swift. -- [x] **It can be implemented in storyboard without a single line of [code](#code-less-storyboard-implementation).** -- [x] Four standard animation styles to choose from (even parallax if you want to get weird). -- [x] Highly customizable without needing to write tons of custom code. -- [x] Supports continuous swiping between side menus on boths sides in a single gesture. -- [x] Global menu configuration. Set-up once and be done for all screens. -- [x] Menus can be presented and dismissed the same as any other View Controller since this control uses custom transitions. +* **It can be implemented in storyboard without a single line of [code](#code-less-storyboard-implementation).** +* Four standard animation styles to choose from (even parallax if you want to get weird). +* Highly customizable without needing to write tons of custom code. +* Supports continuous swiping between side menus on boths sides in a single gesture. +* Global menu configuration. Set-up once and be done for all screens. +* Menus can be presented and dismissed the same as any other View Controller since this control uses custom transitions. Check out the example project to see it in action! ### Preview Samples @@ -26,7 +26,7 @@ Check out the example project to see it in action! | ![](etc/SlideOut.gif) | ![](etc/SlideIn.gif) | ![](etc/Dissolve.gif) | ![](etc/InOut.gif) | ## Requirements -- [x] iOS 8 or higher +* iOS 8 or higher ## Installation ### CocoaPods From 8f4e9ee21458b28f483cb9319e5afce36fb999a0 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Tue, 24 Jan 2017 21:31:42 -0800 Subject: [PATCH 23/23] Remove unused variable. --- Pod/Classes/UISideMenuNavigationController.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index 89fbbb1..fd80ac7 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -183,7 +183,6 @@ open class UISideMenuNavigationController: UINavigationController { viewController.navigationItem.hidesBackButton = true } case .replace: - var viewControllers = navigationController.viewControllers viewController.navigationItem.hidesBackButton = true navigationController.setViewControllers([viewController], animated: animated) CATransaction.commit()