From c8ede5cd763d0be947152ea7b7afff40a19f6027 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Sat, 14 May 2016 01:33:17 -0700 Subject: [PATCH 1/3] - Refactoring to simplify SideMenuManager logic. - Fix for crashes by preventing side menus from being modified while actively presented. --- Pod/Classes/SideMenuManager.swift | 145 +++++++++--------- .../UISideMenuNavigationController.swift | 6 +- 2 files changed, 76 insertions(+), 75 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index 9f93fdb..38b066f 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -24,9 +24,6 @@ public class SideMenuManager { case ViewSlideInOut case MenuDissolveIn } - - private static var originalLeftMenuBackgroundColor: UIColor? - private static var originalRightMenuBackgroundColor: UIColor? // Bounds which has been allocated for the app on the whole device screen internal static var appScreenRect: CGRect { @@ -111,117 +108,120 @@ public class SideMenuManager { */ public static var menuBlurEffectStyle: UIBlurEffectStyle? { didSet { - updateMenuBlurIfNecessary() + if oldValue != menuBlurEffectStyle { + updateMenuBlurIfNecessary() + } } } /// The left menu. public static var menuLeftNavigationController: UISideMenuNavigationController? { willSet { - if menuLeftNavigationController != nil { - let originalBlurEffectStyle = menuBlurEffectStyle - menuBlurEffectStyle = nil - updateMenuBlurIfNecessary() - menuBlurEffectStyle = originalBlurEffectStyle + if menuLeftNavigationController?.presentingViewController == nil { + removeMenuBlurForMenu(menuLeftNavigationController) } } didSet { - if let menuLeftNavigationController = menuLeftNavigationController { - let exitPanGesture = UIPanGestureRecognizer() - exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:))) - menuLeftNavigationController.view.addGestureRecognizer(exitPanGesture) - menuLeftNavigationController.transitioningDelegate = SideMenuTransition.singleton - menuLeftNavigationController.modalPresentationStyle = .OverFullScreen - if !menuLeftNavigationController.leftSide { - menuLeftNavigationController.leftSide = true - } - menuLeftSwipeToDismissGesture = exitPanGesture - updateMenuBlurIfNecessary() + guard oldValue?.presentingViewController == nil else { + print("SideMenu Warning: menuLeftNavigationController cannot be modified while it's presented.") + menuLeftNavigationController = oldValue + return } + setupNavigationController(menuLeftNavigationController, leftSide: true) } } /// The right menu. public static var menuRightNavigationController: UISideMenuNavigationController? { willSet { - if menuRightNavigationController != nil { - let originalBlurEffectStyle = menuBlurEffectStyle - menuBlurEffectStyle = nil - updateMenuBlurIfNecessary() - menuBlurEffectStyle = originalBlurEffectStyle + if menuRightNavigationController?.presentingViewController == nil { + removeMenuBlurForMenu(menuRightNavigationController) } } didSet { - if let menuRightNavigationController = menuRightNavigationController { - let exitPanGesture = UIPanGestureRecognizer() - exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:))) - menuRightNavigationController.view.addGestureRecognizer(exitPanGesture) - menuRightNavigationController.transitioningDelegate = SideMenuTransition.singleton - menuRightNavigationController.modalPresentationStyle = .OverFullScreen - if menuRightNavigationController.leftSide { - menuRightNavigationController.leftSide = false - } - menuRightSwipeToDismissGesture = exitPanGesture - updateMenuBlurIfNecessary() + guard oldValue?.presentingViewController == nil else { + print("SideMenu Warning: menuRightNavigationController cannot be modified while it's presented.") + menuRightNavigationController = oldValue + return } + setupNavigationController(menuRightNavigationController, leftSide: false) } } + private class func setupNavigationController(forMenu: UISideMenuNavigationController?, leftSide: Bool) { + guard let forMenu = forMenu else { + return + } + + let exitPanGesture = UIPanGestureRecognizer() + exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:))) + forMenu.view.addGestureRecognizer(exitPanGesture) + forMenu.transitioningDelegate = SideMenuTransition.singleton + forMenu.modalPresentationStyle = .OverFullScreen + forMenu.leftSide = leftSide + if leftSide { + menuLeftSwipeToDismissGesture = exitPanGesture + } else { + menuRightSwipeToDismissGesture = exitPanGesture + } + updateMenuBlurIfNecessary() + } + private class func updateMenuBlurIfNecessary() { - if let menuLeftNavigationController = menuLeftNavigationController, let view = menuLeftNavigationController.visibleViewController?.view { - if !UIAccessibilityIsReduceTransparencyEnabled() && menuBlurEffectStyle != nil { - if originalLeftMenuBackgroundColor == nil { - originalLeftMenuBackgroundColor = view.backgroundColor - } - setupMenuBlurForMenu(menuLeftNavigationController) - } else if originalLeftMenuBackgroundColor != nil { - removeMenuBlurForMenu(menuLeftNavigationController) - view.backgroundColor = originalLeftMenuBackgroundColor! - originalLeftMenuBackgroundColor = nil + let menuBlurBlock = { (forMenu: UISideMenuNavigationController?) in + if let forMenu = forMenu { + setupMenuBlurForMenu(forMenu) } } - if let menuRightNavigationController = menuRightNavigationController, let view = menuRightNavigationController.visibleViewController?.view { - if !UIAccessibilityIsReduceTransparencyEnabled() && menuBlurEffectStyle != nil { - if originalRightMenuBackgroundColor == nil { - originalRightMenuBackgroundColor = view.backgroundColor - } - setupMenuBlurForMenu(menuRightNavigationController) - } else if originalRightMenuBackgroundColor != nil { - removeMenuBlurForMenu(menuRightNavigationController) - view.backgroundColor = originalRightMenuBackgroundColor! - originalRightMenuBackgroundColor = nil - } - } + menuBlurBlock(menuLeftNavigationController) + menuBlurBlock(menuRightNavigationController) } - private class func setupMenuBlurForMenu(forMenu: UINavigationController) { + private class func setupMenuBlurForMenu(forMenu: UISideMenuNavigationController?) { removeMenuBlurForMenu(forMenu) + + guard let forMenu = forMenu, + menuBlurEffectStyle = menuBlurEffectStyle, + view = forMenu.visibleViewController?.view + where !UIAccessibilityIsReduceTransparencyEnabled() else { + return + } + + if forMenu.originalMenuBackgroundColor == nil { + forMenu.originalMenuBackgroundColor = view.backgroundColor + } + + let blurEffect = UIBlurEffect(style: menuBlurEffectStyle) + let blurView = UIVisualEffectView(effect: blurEffect) + view.backgroundColor = UIColor.clearColor() if let tableViewController = forMenu.visibleViewController as? UITableViewController { - tableViewController.tableView.backgroundColor = UIColor.clearColor() - - let blurEffect = UIBlurEffect(style: menuBlurEffectStyle!) - tableViewController.tableView.backgroundView = UIVisualEffectView(effect: blurEffect) + tableViewController.tableView.backgroundView = blurView tableViewController.tableView.separatorEffect = UIVibrancyEffect(forBlurEffect: blurEffect) tableViewController.tableView.reloadData() - } else if let viewController = forMenu.visibleViewController { - viewController.view.backgroundColor = UIColor.clearColor() - - let blurView = UIVisualEffectView(effect: UIBlurEffect(style: menuBlurEffectStyle!)) + } else { blurView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth] - blurView.frame = viewController.view.bounds - - viewController.view.insertSubview(blurView, atIndex: 0) + blurView.frame = view.bounds + view.insertSubview(blurView, atIndex: 0) } } - private class func removeMenuBlurForMenu(forMenu: UINavigationController) { + private class func removeMenuBlurForMenu(forMenu: UISideMenuNavigationController?) { + guard let forMenu = forMenu, + originalMenuBackgroundColor = forMenu.originalMenuBackgroundColor, + view = forMenu.visibleViewController?.view else { + return + } + + view.backgroundColor = originalMenuBackgroundColor + forMenu.originalMenuBackgroundColor = nil + if let tableViewController = forMenu.visibleViewController as? UITableViewController { tableViewController.tableView.backgroundView = nil tableViewController.tableView.separatorEffect = nil tableViewController.tableView.reloadData() } else if let viewController = forMenu.visibleViewController { - if let blurView = viewController.view.subviews[0] as? UIVisualEffectView { + if let blurView = view.subviews[0] as? UIVisualEffectView { blurView.removeFromSuperview() } } @@ -236,7 +236,6 @@ public class SideMenuManager { - Returns: The array of screen edge gestures added to `toView`. */ public class func menuAddScreenEdgePanGesturesToPresent(toView toView: UIView, forMenu:UIRectEdge? = nil) -> [UIScreenEdgePanGestureRecognizer] { - var array = [UIScreenEdgePanGestureRecognizer]() if forMenu != .Right { diff --git a/Pod/Classes/UISideMenuNavigationController.swift b/Pod/Classes/UISideMenuNavigationController.swift index 9d6cc93..867c01b 100644 --- a/Pod/Classes/UISideMenuNavigationController.swift +++ b/Pod/Classes/UISideMenuNavigationController.swift @@ -9,6 +9,8 @@ import UIKit public class UISideMenuNavigationController: UINavigationController { + internal var originalMenuBackgroundColor: UIColor? + public override func awakeFromNib() { super.awakeFromNib() @@ -21,7 +23,7 @@ public class UISideMenuNavigationController: UINavigationController { /// Whether the menu appears on the right or left side of the screen. Right is the default. @IBInspectable public var leftSide:Bool = false { didSet { - if isViewLoaded() { // suppress warnings + if isViewLoaded() && oldValue != leftSide { // suppress warnings didSetSide() } } @@ -148,7 +150,7 @@ public class UISideMenuNavigationController: UINavigationController { CATransaction.commit() } else { menuViewController.presentViewController(viewController, animated: animated, completion: nil) - print("Warning: attempted to push a ViewController from a ViewController that doesn't have a NavigationController. It will be presented it instead.") + print("SideMenu Warning: cannot push a ViewController from a ViewController without a NavigationController. It will be presented it instead.") } } } From 771047f506143efd938a4ec274d00be7591d6800 Mon Sep 17 00:00:00 2001 From: jonkykong Date: Sat, 14 May 2016 01:37:08 -0700 Subject: [PATCH 2/3] Updated pod spec and README for cocoa pods. --- README.md | 14 +++++++------- SideMenu.podspec | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 12045c6..d192a6e 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,19 @@ [![Platform](https://img.shields.io/cocoapods/p/SideMenu.svg?style=flat)](http://cocoapods.org/pods/SideMenu) ## Shameless Requests First -**1. If you like SideMenu, give it a ★ at the top right of this page.** +**1. If you like SideMenu, give it a ★ at the top right of its [GitHub](https://github.com/jonkykong/SideMenu) page.** **2. I need an invite to Dribbble to share SideMenu. Invite me: https://dribbble.com/jonkykong** ## 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 or this [interactive demo](https://appetize.io/app/64a9v3e6b8c6f53zvn5pnny80m) to see it in action! diff --git a/SideMenu.podspec b/SideMenu.podspec index 17848c0..2d9a934 100644 --- a/SideMenu.podspec +++ b/SideMenu.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = "SideMenu" - s.version = "1.1.6" + s.version = "1.1.7" 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 1e6f192e281623f7350bedc6a3db4c9f66f1e19f Mon Sep 17 00:00:00 2001 From: jonkykong Date: Sat, 14 May 2016 01:42:19 -0700 Subject: [PATCH 3/3] Removed unneeded declaration. --- Pod/Classes/SideMenuManager.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Pod/Classes/SideMenuManager.swift b/Pod/Classes/SideMenuManager.swift index 38b066f..4e41c5b 100644 --- a/Pod/Classes/SideMenuManager.swift +++ b/Pod/Classes/SideMenuManager.swift @@ -220,10 +220,8 @@ public class SideMenuManager { tableViewController.tableView.backgroundView = nil tableViewController.tableView.separatorEffect = nil tableViewController.tableView.reloadData() - } else if let viewController = forMenu.visibleViewController { - if let blurView = view.subviews[0] as? UIVisualEffectView { - blurView.removeFromSuperview() - } + } else if let blurView = view.subviews[0] as? UIVisualEffectView { + blurView.removeFromSuperview() } }