Compare commits

..

46 Commits

Author SHA1 Message Date
jonkykong a1716035c3 Update README for Cocoapods. 2017-01-12 14:17:04 -08:00
jonkykong 99456afaed Update pod spec. 2017-01-12 14:16:49 -08:00
jonkykong 4b92f5a776 Refactoring. 2017-01-12 14:14:05 -08:00
jonkykong 459a4a1e9f Second fix for multiple gestures actuating and causing problem. 2017-01-12 14:13:43 -08:00
jonkykong 717fd3a325 Update README for GitHub. 2017-01-10 13:13:59 -08:00
jonkykong 802146708e Merge tag '2.1.4'
* tag '2.1.4':
  Silence warning.
  Update README for Cocoapods.
  Update podspec.
  Fix for multiple gestures causing crashes when presenting or dismissing menu. SideMenuTransition is due for a refactoring of logic to simplify that I don’t have time for now.
  Update to Launch Screen.
  Say “SideMenu” instead of “Example” in demo project.
2017-01-10 13:13:04 -08:00
jonkykong f34452d040 Updating README for GitHub. 2017-01-09 12:49:17 -08:00
jonkykong bda990bbef Silence warning. 2017-01-09 12:41:27 -08:00
jonkykong b8f13dc333 Update README for Cocoapods. 2017-01-09 12:36:07 -08:00
jonkykong 793ffd77bc Update podspec. 2017-01-09 12:35:09 -08:00
jonkykong 132a50766e Fix for multiple gestures causing crashes when presenting or dismissing menu. SideMenuTransition is due for a refactoring of logic to simplify that I don’t have time for now. 2017-01-09 12:34:10 -08:00
jonkykong 85f00c63b4 Update to Launch Screen. 2017-01-09 12:32:11 -08:00
jonkykong e71ec145f1 Say “SideMenu” instead of “Example” in demo project. 2017-01-09 12:31:44 -08:00
jonkykong 37b0f6d57e Update README for GitHub. 2017-01-06 23:21:25 -08:00
jonkykong ccee3e1f83 Merge tag '2.1.3'
* tag '2.1.3':
  Update podspec and README for Cocoapods.
  Cleaner version of logic proposed by @saltyskip.
  adding possibility of tab bar or nav bar
  make tab bar controller
2017-01-06 23:17:38 -08:00
jonkykong 1786b459c5 Update podspec and README for Cocoapods. 2017-01-06 23:14:40 -08:00
jonkykong 5f5fdcba7a Merge branch 'pr/125' into 2.1.3
* pr/125:
  Cleaner version of logic proposed by @saltyskip.
  adding possibility of tab bar or nav bar
  make tab bar controller
2017-01-06 23:12:43 -08:00
jonkykong 27f490435e Cleaner version of logic proposed by @saltyskip. 2017-01-06 23:11:50 -08:00
Jon Kent 96dd886575 Update ISSUE_TEMPLATE.md 2017-01-04 11:03:59 -08:00
andrei 5b4b6afdbe adding possibility of tab bar or nav bar 2017-01-04 18:34:20 +09:00
andrei fa6f9eb9e1 make tab bar controller 2017-01-04 17:54:29 +09:00
Jon Kent 0c3aaa471d Update README.md 2016-12-30 17:59:42 -08:00
jonkykong f184415f7c Ready correction. 2016-12-28 18:34:08 -06:00
jonkykong 1c883abf55 Updated readme for Github. 2016-12-28 15:08:25 -06:00
jonkykong f82138dc87 Merge tag '2.1.2'
* tag '2.1.2':
  Updated podspec/readme.
  Removed redundant copies of source files causing confusion with updating cocoa pods. Replaced with links to pod files. Unsure if this will break Carthage.
  Cocoapods still not updating. Updating podspec in prep for next workaround.
  Reversing edit.
  Making frivolous change to file not updating to attempt redetection.
  Cocoapods still not updating. Updated podspec.
  Cocoapods does not appear to have updated… retrying.
2016-12-28 15:08:06 -06:00
jonkykong 56f5270405 Updated podspec/readme. 2016-12-28 15:02:05 -06:00
jonkykong 0c1086a9da Removed redundant copies of source files causing confusion with updating cocoa pods. Replaced with links to pod files. Unsure if this will break Carthage. 2016-12-28 14:46:38 -06:00
jonkykong 138a13bd60 Cocoapods still not updating. Updating podspec in prep for next workaround. 2016-12-28 14:13:51 -06:00
jonkykong 430fad0568 Reversing edit. 2016-12-28 14:08:35 -06:00
jonkykong d8d19b6207 Making frivolous change to file not updating to attempt redetection. 2016-12-28 14:08:19 -06:00
jonkykong eaa6d2f86f Cocoapods still not updating. Updated podspec. 2016-12-28 14:07:57 -06:00
jonkykong 2a35158c3c Cocoapods does not appear to have updated… retrying. 2016-12-28 13:49:52 -06:00
jonkykong 9f454c8fc9 Update readme for Github. 2016-12-28 13:18:25 -06:00
jonkykong fedff5a09e Merge tag '2.0.8'
* tag '2.0.8':
  Updated pod spec/readme.
  Updated project settings.
  Refactor of logic for menuEnableSwipeGestures so it won’t conflict with swipe based controls (UISlider) in menu.
2016-12-28 13:18:05 -06:00
jonkykong 065e6e236e Updated pod spec/readme. 2016-12-28 13:04:30 -06:00
jonkykong 143a8cdde9 Updated project settings. 2016-12-28 13:01:46 -06:00
jonkykong cadb63bf21 Merge branch 'master' into 2.0.8
* master:
  Update CONTRIBUTING.md
  Update README.md
  Update README.md
  Update ISSUE_TEMPLATE.md
  Update ISSUE_TEMPLATE.md
  Update ISSUE_TEMPLATE.md
  Create ISSUE_TEMPLATE.md
  Create CONTRIBUTING.md
  Silence warning of unused variable.
2016-12-28 12:59:59 -06:00
jonkykong 6903ffb958 Refactor of logic for menuEnableSwipeGestures so it won’t conflict with swipe based controls (UISlider) in menu. 2016-12-28 12:56:55 -06:00
Jon Kent ac5c1eaba6 Update CONTRIBUTING.md 2016-12-21 12:27:10 -06:00
Jon Kent db4eb5380d Update README.md 2016-12-17 20:04:56 -08:00
Jon Kent 5d08277cd4 Update README.md 2016-12-15 11:49:09 -08:00
Jon Kent 2798c61d73 Update ISSUE_TEMPLATE.md 2016-12-14 20:54:40 -08:00
Jon Kent 8037148fd2 Update ISSUE_TEMPLATE.md 2016-12-14 20:54:18 -08:00
Jon Kent 2b8e46d503 Update ISSUE_TEMPLATE.md 2016-12-14 20:46:55 -08:00
Jon Kent 49841b0b4e Create ISSUE_TEMPLATE.md 2016-12-14 20:41:46 -08:00
Jon Kent 516e845da7 Create CONTRIBUTING.md 2016-12-14 20:20:04 -08:00
15 changed files with 203 additions and 1115 deletions
+17
View File
@@ -0,0 +1,17 @@
# Contribution Guidelines
Thank you for your interest in SideMenu!
I have received a surprising amount of questions about SideMenu since putting it up here. A few people in the community have identified some problems and helped contribute to SideMenu to make it better for everyone and I'm truly grateful for the support! Keep them coming!
I have also received a number of questions about people having issues implementing SideMenu, mostly from beginners learning how to code. As much as I would love to help all of you, I simply do **not** have the time to teach you. That's why I spent a lot of time putting together a detailed [README](https://github.com/jonkykong/SideMenu/blob/master/README.md), adding comments about usage in code, and providing a [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example). These will give you all the information you need to work through any problem and also save me the time it takes to personally respond. **It is faster for you to figure it out for yourself instead of waiting for me to respond to you.**
### If your question begins with _"How do I..."_
- It's **not** a bug. Stay persistent, try a few different things, and you will figure it out! I also recommend searching and posting your questions on [stackoverflow.com](stackoverflow.com). Or, if you're interested in hiring me to teach you, please email me using the email address listed at the top of my [README](https://github.com/jonkykong/SideMenu/blob/master/README.md).
### If your question begins with _"Can I..."_
- That's a **new feature request**. I am no longer investing my personal time to implement one-off features because SideMenu currently meets the majority of people's needs with the features it already has. However, this is a great opportunity for you to contribute to this open source project! Feel free to open an issue to ask any clarifying questions for your new feature before you start building. Open a [pull request](https://github.com/jonkykong/SideMenu/pull/new/master) when you're ready for me to merge it.
**Again**, please do **not** email me or open any issues if you want to know how to use SideMenu or are having trouble getting it to work. However, if you think you found a bug, open an issue and I will respond to it as quickly as I can. You should be able to demonstrate the bug in the [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example) which has a minimal amount of code.
Thanks again for your support and for being respectful of my time.
+12
View File
@@ -0,0 +1,12 @@
<!--- Provide a general summary of your changes in the Title above -->
<!--- IF YOU DELETE OR IGNORE THIS TEMPLATE WHEN OPENING A NEW ISSUE, YOUR ISSUE WILL BE IGNORED -->
## New Issue Checklist
<!--- Please complete all of the checks below before submitting a new issue -->
I have read the [guidelines for contributing](https://github.com/jonkykong/SideMenu/blob/master/.github/CONTRIBUTING.md) and I understand:
- [ ] My issue was **not** solved in the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md).
- [ ] My issue can **not** be answered on [stackoverflow.com](stackoverflow.com).
- [ ] My issue is **not** a request for new functionality that I am unwilling to build and contribute with a pull request.
- [ ] My issue **is** reproducible in the [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example).
## Issue Description
<!--- After completing all of the checks above, describe the issue here -->
+2
View File
@@ -4,6 +4,8 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>SideMenu</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
+10 -4
View File
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -18,12 +22,14 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2016 jonkykong. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2016 Jon Kent. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
<rect key="frame" x="20" y="626.5" width="335" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SideMenu" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="20" y="202" width="335" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
+22 -13
View File
@@ -81,9 +81,6 @@ open class SideMenuManager : NSObject {
/// The right menu swipe to dismiss gesture.
open static weak var menuRightSwipeToDismissGesture: UIPanGestureRecognizer?
/// Enable or disable gestures that would swipe to present or dismiss the menu. Default is true.
open static var menuEnableSwipeGestures: Bool = true
/// Enable or disable interaction with the presenting view controller while the menu is displayed. Enabling may make it difficult to dismiss the menu or cause exceptions if the user tries to present and already presented menu. Default is false.
open static var menuPresentingViewControllerUserInteractionEnabled: Bool = false
@@ -165,20 +162,32 @@ open class SideMenuManager : NSObject {
return
}
let exitPanGesture = UIPanGestureRecognizer()
exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
forMenu.view.addGestureRecognizer(exitPanGesture)
if menuEnableSwipeGestures {
let exitPanGesture = UIPanGestureRecognizer()
exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
forMenu.view.addGestureRecognizer(exitPanGesture)
if leftSide {
menuLeftSwipeToDismissGesture = exitPanGesture
} else {
menuRightSwipeToDismissGesture = exitPanGesture
}
}
forMenu.transitioningDelegate = SideMenuTransition.singleton
forMenu.modalPresentationStyle = .overFullScreen
forMenu.leftSide = leftSide
if leftSide {
menuLeftSwipeToDismissGesture = exitPanGesture
} else {
menuRightSwipeToDismissGesture = exitPanGesture
}
updateMenuBlurIfNecessary()
}
/// Enable or disable gestures that would swipe to present or dismiss the menu. Default is true.
open static var menuEnableSwipeGestures: Bool = true {
didSet {
menuLeftSwipeToDismissGesture?.view?.removeGestureRecognizer(menuLeftSwipeToDismissGesture!)
menuRightSwipeToDismissGesture?.view?.removeGestureRecognizer(menuRightSwipeToDismissGesture!)
setupNavigationController(menuLeftNavigationController, leftSide: true)
setupNavigationController(menuRightNavigationController, leftSide: false)
}
}
fileprivate class func updateMenuBlurIfNecessary() {
let menuBlurBlock = { (forMenu: UISideMenuNavigationController?) in
if let forMenu = forMenu {
@@ -197,7 +206,7 @@ open class SideMenuManager : NSObject {
let menuBlurEffectStyle = menuBlurEffectStyle,
let view = forMenu.visibleViewController?.view
, !UIAccessibilityIsReduceTransparencyEnabled() else {
return
return
}
if forMenu.originalMenuBackgroundColor == nil {
@@ -222,7 +231,7 @@ open class SideMenuManager : NSObject {
guard let forMenu = forMenu,
let originalMenuBackgroundColor = forMenu.originalMenuBackgroundColor,
let view = forMenu.visibleViewController?.view else {
return
return
}
view.backgroundColor = originalMenuBackgroundColor
+95 -90
View File
@@ -17,8 +17,35 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr
internal static let singleton = SideMenuTransition()
internal static var presentDirection: UIRectEdge = .left;
internal static weak var tapView: UIView?
internal static weak var statusBarView: UIView?
internal static weak var tapView: UIView? {
didSet {
guard let tapView = tapView else {
return
}
tapView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
let exitPanGesture = UIPanGestureRecognizer()
exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
let exitTapGesture = UITapGestureRecognizer()
exitTapGesture.addTarget(SideMenuTransition.self, action: #selector(SideMenuTransition.handleHideMenuTap(_:)))
tapView.addGestureRecognizer(exitPanGesture)
tapView.addGestureRecognizer(exitTapGesture)
}
}
internal static weak var statusBarView: UIView? {
didSet {
guard let statusBarView = statusBarView else {
return
}
if let menuShrinkBackgroundColor = SideMenuManager.menuAnimationBackgroundColor {
statusBarView.backgroundColor = menuShrinkBackgroundColor
} else {
statusBarView.backgroundColor = UIColor.black
}
statusBarView.isUserInteractionEnabled = false
}
}
// prevent instantiation
fileprivate override init() {}
@@ -58,10 +85,6 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr
}
internal class func handlePresentMenuPan(_ pan: UIPanGestureRecognizer) {
guard SideMenuManager.menuEnableSwipeGestures else {
return
}
// how much distance have we panned in reference to the parent view?
guard let view = viewControllerForPresentedMenu != nil ? viewControllerForPresentedMenu?.view : pan.view else {
return
@@ -125,10 +148,6 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr
}
internal class func handleHideMenuPan(_ pan: UIPanGestureRecognizer) {
if !SideMenuManager.menuEnableSwipeGestures {
return
}
let translation = pan.translation(in: pan.view!)
let direction:CGFloat = SideMenuTransition.presentDirection == .left ? -1 : 1
let distance = translation.x / SideMenuManager.menuWidth * direction
@@ -162,7 +181,9 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr
internal class func hideMenuStart() {
NotificationCenter.default.removeObserver(SideMenuTransition.singleton)
guard let mainViewController = SideMenuTransition.viewControllerForPresentedMenu,
let menuView = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController?.view : SideMenuManager.menuRightNavigationController?.view else {return}
let menuView = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController?.view : SideMenuManager.menuRightNavigationController?.view else {
return
}
menuView.transform = CGAffineTransform.identity
mainViewController.view.transform = CGAffineTransform.identity
@@ -300,67 +321,45 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView
// prevent any other menu gestures from firing
container.isUserInteractionEnabled = false
if let menuBackgroundColor = SideMenuManager.menuAnimationBackgroundColor {
container.backgroundColor = menuBackgroundColor
}
// create a tuple of our screens
let screens : (from:UIViewController, to:UIViewController) = (transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!, transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!)
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
// assign references to our menu view controller and the 'bottom' view controller from the tuple
// remember that our menuViewController will alternate between the from and to view controller depending if we're presenting or dismissing
let menuViewController = (!presenting ? screens.from : screens.to)
let topViewController = !presenting ? screens.to : screens.from
let menuViewController = presenting ? toViewController : fromViewController
let topViewController = presenting ? fromViewController : toViewController
let menuView = menuViewController.view
let topView = topViewController.view
let menuView = menuViewController.view!
let topView = topViewController.view!
// prepare menu items to slide in
if presenting {
var tapView: UIView?
if !SideMenuManager.menuPresentingViewControllerUserInteractionEnabled {
tapView = UIView()
tapView!.autoresizingMask = [.flexibleHeight, .flexibleWidth]
let exitPanGesture = UIPanGestureRecognizer()
exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
let exitTapGesture = UITapGestureRecognizer()
exitTapGesture.addTarget(SideMenuTransition.self, action: #selector(SideMenuTransition.handleHideMenuTap(_:)))
tapView!.addGestureRecognizer(exitPanGesture)
tapView!.addGestureRecognizer(exitTapGesture)
SideMenuTransition.tapView = tapView
}
SideMenuTransition.originalSuperview = topView?.superview
SideMenuTransition.originalSuperview = topView.superview
// add the both views to our view controller
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
container.addSubview(menuView!)
container.addSubview(topView!)
if let tapView = tapView {
topView?.addSubview(tapView)
}
container.addSubview(menuView)
container.addSubview(topView)
case .menuSlideIn, .menuDissolveIn:
container.addSubview(topView!)
if let tapView = tapView {
container.addSubview(tapView)
}
container.addSubview(menuView!)
container.addSubview(topView)
container.addSubview(menuView)
}
if SideMenuManager.menuFadeStatusBar {
let blackBar = UIView()
if let menuShrinkBackgroundColor = SideMenuManager.menuAnimationBackgroundColor {
blackBar.backgroundColor = menuShrinkBackgroundColor
} else {
blackBar.backgroundColor = UIColor.black
}
blackBar.isUserInteractionEnabled = false
container.addSubview(blackBar)
SideMenuTransition.statusBarView = blackBar
let statusBarView = UIView()
SideMenuTransition.statusBarView = statusBarView
container.addSubview(statusBarView)
}
SideMenuTransition.hideMenuStart() // offstage for interactive
SideMenuTransition.hideMenuStart()
}
// perform the animation!
@@ -368,53 +367,59 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewContr
let options: UIViewAnimationOptions = interactive ? .curveLinear : UIViewAnimationOptions()
UIView.animate(withDuration: duration, delay: 0, options: options, animations: { () -> Void in
if self.presenting {
SideMenuTransition.presentMenuStart() // onstage items: slide in
SideMenuTransition.presentMenuStart()
} else {
SideMenuTransition.hideMenuStart()
}
menuView?.isUserInteractionEnabled = false
}) { (finished) -> Void in
// tell our transitionContext object that we've finished animating
if transitionContext.transitionWasCancelled {
let viewControllerForPresentedMenu = SideMenuTransition.viewControllerForPresentedMenu
if self.presenting {
SideMenuTransition.hideMenuComplete()
} else {
SideMenuTransition.presentMenuComplete()
}
menuView?.isUserInteractionEnabled = true
transitionContext.completeTransition(false)
if SideMenuTransition.switchMenus {
SideMenuTransition.switchMenus = false
viewControllerForPresentedMenu?.present(SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController! : SideMenuManager.menuRightNavigationController!, animated: true, completion: nil)
}
return
}
}) { (finished) -> Void in
container.isUserInteractionEnabled = true
// tell our transitionContext object that we've finished animating
if transitionContext.transitionWasCancelled {
let viewControllerForPresentedMenu = SideMenuTransition.viewControllerForPresentedMenu
if self.presenting {
SideMenuTransition.hideMenuComplete()
} else {
SideMenuTransition.presentMenuComplete()
menuView?.isUserInteractionEnabled = true
transitionContext.completeTransition(true)
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
container.addSubview(topView!)
case .menuSlideIn, .menuDissolveIn:
container.insertSubview(topView!, at: 0)
}
if let statusBarView = SideMenuTransition.statusBarView {
container.bringSubview(toFront: statusBarView)
}
return
}
SideMenuTransition.hideMenuComplete()
transitionContext.completeTransition(false)
if SideMenuTransition.switchMenus {
SideMenuTransition.switchMenus = false
viewControllerForPresentedMenu?.present(SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController! : SideMenuManager.menuRightNavigationController!, animated: true, completion: nil)
}
return
}
if self.presenting {
SideMenuTransition.presentMenuComplete()
if !SideMenuManager.menuPresentingViewControllerUserInteractionEnabled {
let tapView = UIView()
topView.addSubview(tapView)
tapView.frame = topView.bounds
SideMenuTransition.tapView = tapView
}
transitionContext.completeTransition(true)
menuView?.removeFromSuperview()
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
container.addSubview(topView)
case .menuSlideIn, .menuDissolveIn:
container.insertSubview(topView, at: 0)
}
if let statusBarView = SideMenuTransition.statusBarView {
container.bringSubview(toFront: statusBarView)
}
return
}
SideMenuTransition.hideMenuComplete()
transitionContext.completeTransition(true)
menuView.removeFromSuperview()
}
}
@@ -125,9 +125,10 @@ open class UISideMenuNavigationController: UINavigationController {
super.pushViewController(viewController, animated: animated)
return
}
guard let presentingViewController = presentingViewController as? UINavigationController else {
print("SideMenu Warning: attempt to push a View Controller from \(self.presentingViewController.self) where its navigationController == nil. It must be embedded in a Navigation Controller for this to work.")
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.")
return
}
@@ -144,9 +145,9 @@ open class UISideMenuNavigationController: UINavigationController {
})
if SideMenuManager.menuAllowPopIfPossible {
for subViewController in presentingViewController.viewControllers {
for subViewController in navigationController.viewControllers {
if type(of: subViewController) == type(of: viewController) {
presentingViewController.popToViewController(subViewController, animated: animated)
navigationController.popToViewController(subViewController, animated: animated)
CATransaction.commit()
return
}
@@ -154,22 +155,20 @@ open class UISideMenuNavigationController: UINavigationController {
}
if SideMenuManager.menuReplaceOnPush {
var viewControllers = presentingViewController.viewControllers
var viewControllers = navigationController.viewControllers
viewControllers.removeLast()
viewControllers.append(viewController)
presentingViewController.setViewControllers(viewControllers, animated: animated)
navigationController.setViewControllers(viewControllers, animated: animated)
CATransaction.commit()
return
}
if let lastViewController = presentingViewController.viewControllers.last, !SideMenuManager.menuAllowPushOfSameClassTwice {
if type(of: lastViewController) == type(of: viewController) {
CATransaction.commit()
return
}
if let lastViewController = navigationController.viewControllers.last, !SideMenuManager.menuAllowPushOfSameClassTwice && type(of: lastViewController) == type(of: viewController) {
CATransaction.commit()
return
}
presentingViewController.pushViewController(viewController, animated: animated)
navigationController.pushViewController(viewController, animated: animated)
CATransaction.commit()
}
}
+10 -15
View File
@@ -4,17 +4,19 @@
[![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.
My name is Jon Kent and I'm a freelance iOS designer, developer, and mobile strategist. 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.*
## 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!
@@ -24,7 +26,7 @@ Check out the example project to see it in action!
![](etc/InOut.gif)
## Requirements
- [x] iOS 8 or higher
* iOS 8 or higher
## Installation
### CocoaPods
@@ -224,13 +226,6 @@ Don't try to change the status bar appearance when presenting a menu. When used
## Thank You
A special thank you to everyone that has [contributed](https://github.com/jonkykong/SideMenu/graphs/contributors) to this library to make it better. Your support is appreciated!
## About Me
My name is Jon Kent and I'm a freelance iOS designer, developer, and mobile strategist. I love coffee and play the drums. **Hire me!**
🌎 Web: [http://jonkent.me](http://jonkent.me)
✉️ Email: [contact@jonkent.me](mailto:contact@jonkent.me) **IMPORTANT: Before emailing me, please read [this](https://github.com/jonkykong/SideMenu/issues/58).**
## License
SideMenu is available under the MIT license. See the LICENSE file for more info.
+1 -1
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = "SideMenu"
s.version = "2.0.7"
s.version = "2.1.5"
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.
+21 -17
View File
@@ -10,10 +10,6 @@
108F6C478E56A4CA081F8E09 /* Pods_Example_ExampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52C8DD7BE43A8987854CA726 /* Pods_Example_ExampleTests.framework */; };
456193561EADC00AC505B531 /* Pods_ExampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1435FAD2F735E43F383BE96 /* Pods_ExampleTests.framework */; };
65FF1B3E1DE321D8007B0845 /* SideMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = 65FF1B3D1DE321D8007B0845 /* SideMenu.h */; settings = {ATTRIBUTES = (Public, ); }; };
65FF1B441DE331D9007B0845 /* SideMenuManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF1B401DE331D9007B0845 /* SideMenuManager.swift */; };
65FF1B451DE331D9007B0845 /* SideMenuTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF1B411DE331D9007B0845 /* SideMenuTransition.swift */; };
65FF1B461DE331D9007B0845 /* UISideMenuNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF1B421DE331D9007B0845 /* UISideMenuNavigationController.swift */; };
65FF1B471DE331D9007B0845 /* UITableViewVibrantCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FF1B431DE331D9007B0845 /* UITableViewVibrantCell.swift */; };
7B48A0D61DCB2487002990A1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B48A0D51DCB2487002990A1 /* AppDelegate.swift */; };
7B48A0DD1DCB2487002990A1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B48A0DC1DCB2487002990A1 /* Assets.xcassets */; };
7B48A0EB1DCB2487002990A1 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B48A0EA1DCB2487002990A1 /* Tests.swift */; };
@@ -22,6 +18,10 @@
7B48A0F81DCB2518002990A1 /* SideMenuTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B48A0F51DCB2518002990A1 /* SideMenuTableView.swift */; };
7B552D5D1DCC65830010301C /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7B552D5C1DCC65830010301C /* Launch Screen.storyboard */; };
7B5FA9B61DCB269700278DF6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7B5FA9B51DCB269700278DF6 /* Main.storyboard */; };
8461A2D31E145A08001DA4F8 /* SideMenuManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8461A2CF1E145A08001DA4F8 /* SideMenuManager.swift */; };
8461A2D41E145A08001DA4F8 /* SideMenuTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8461A2D01E145A08001DA4F8 /* SideMenuTransition.swift */; };
8461A2D51E145A08001DA4F8 /* UISideMenuNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8461A2D11E145A08001DA4F8 /* UISideMenuNavigationController.swift */; };
8461A2D61E145A08001DA4F8 /* UITableViewVibrantCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8461A2D21E145A08001DA4F8 /* UITableViewVibrantCell.swift */; };
84B489B51DD469B000D6CB43 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 84B489B21DD469B000D6CB43 /* LICENSE */; };
84B489B71DD469B000D6CB43 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 84B489B41DD469B000D6CB43 /* README.md */; };
84B489BA1DD469DA00D6CB43 /* SideMenu.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 84B489B91DD469DA00D6CB43 /* SideMenu.podspec */; };
@@ -44,10 +44,6 @@
47896ABC5C8830D88945A8D3 /* Pods_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
52C8DD7BE43A8987854CA726 /* Pods_Example_ExampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example_ExampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
65FF1B3D1DE321D8007B0845 /* SideMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SideMenu.h; path = SideMenu/SideMenu.h; sourceTree = "<group>"; };
65FF1B401DE331D9007B0845 /* SideMenuManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SideMenuManager.swift; path = SideMenu/SideMenuManager.swift; sourceTree = "<group>"; };
65FF1B411DE331D9007B0845 /* SideMenuTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SideMenuTransition.swift; path = SideMenu/SideMenuTransition.swift; sourceTree = "<group>"; };
65FF1B421DE331D9007B0845 /* UISideMenuNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UISideMenuNavigationController.swift; path = SideMenu/UISideMenuNavigationController.swift; sourceTree = "<group>"; };
65FF1B431DE331D9007B0845 /* UITableViewVibrantCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UITableViewVibrantCell.swift; path = SideMenu/UITableViewVibrantCell.swift; sourceTree = "<group>"; };
7B48A0D31DCB2487002990A1 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
7B48A0D51DCB2487002990A1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7B48A0DC1DCB2487002990A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -61,6 +57,10 @@
7B552D5C1DCC65830010301C /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
7B5FA9B51DCB269700278DF6 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
7B9DC9041DC6E8C1000D4007 /* SideMenu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SideMenu.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8461A2CF1E145A08001DA4F8 /* SideMenuManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SideMenuManager.swift; path = Pod/Classes/SideMenuManager.swift; sourceTree = "<group>"; };
8461A2D01E145A08001DA4F8 /* SideMenuTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SideMenuTransition.swift; path = Pod/Classes/SideMenuTransition.swift; sourceTree = "<group>"; };
8461A2D11E145A08001DA4F8 /* UISideMenuNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UISideMenuNavigationController.swift; path = Pod/Classes/UISideMenuNavigationController.swift; sourceTree = "<group>"; };
8461A2D21E145A08001DA4F8 /* UITableViewVibrantCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UITableViewVibrantCell.swift; path = Pod/Classes/UITableViewVibrantCell.swift; sourceTree = "<group>"; };
84B489B21DD469B000D6CB43 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
84B489B41DD469B000D6CB43 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
84B489B91DD469DA00D6CB43 /* SideMenu.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SideMenu.podspec; sourceTree = "<group>"; };
@@ -109,10 +109,10 @@
65FF1B3F1DE33097007B0845 /* Source */ = {
isa = PBXGroup;
children = (
65FF1B401DE331D9007B0845 /* SideMenuManager.swift */,
65FF1B411DE331D9007B0845 /* SideMenuTransition.swift */,
65FF1B421DE331D9007B0845 /* UISideMenuNavigationController.swift */,
65FF1B431DE331D9007B0845 /* UITableViewVibrantCell.swift */,
8461A2CF1E145A08001DA4F8 /* SideMenuManager.swift */,
8461A2D01E145A08001DA4F8 /* SideMenuTransition.swift */,
8461A2D11E145A08001DA4F8 /* UISideMenuNavigationController.swift */,
8461A2D21E145A08001DA4F8 /* UITableViewVibrantCell.swift */,
65FF1B3D1DE321D8007B0845 /* SideMenu.h */,
);
name = Source;
@@ -279,7 +279,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0800;
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0820;
ORGANIZATIONNAME = jonkykong;
TargetAttributes = {
7B48A0D21DCB2487002990A1 = {
@@ -293,6 +293,7 @@
};
7B9DC9031DC6E8C1000D4007 = {
CreatedOnToolsVersion = 8.0;
LastSwiftMigration = 0820;
ProvisioningStyle = Automatic;
};
};
@@ -464,10 +465,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
65FF1B441DE331D9007B0845 /* SideMenuManager.swift in Sources */,
65FF1B451DE331D9007B0845 /* SideMenuTransition.swift in Sources */,
65FF1B461DE331D9007B0845 /* UISideMenuNavigationController.swift in Sources */,
65FF1B471DE331D9007B0845 /* UITableViewVibrantCell.swift in Sources */,
8461A2D51E145A08001DA4F8 /* UISideMenuNavigationController.swift in Sources */,
8461A2D41E145A08001DA4F8 /* SideMenuTransition.swift in Sources */,
8461A2D61E145A08001DA4F8 /* UITableViewVibrantCell.swift in Sources */,
8461A2D31E145A08001DA4F8 /* SideMenuManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -644,6 +645,7 @@
7B9DC90D1DC6E8C1000D4007 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -657,6 +659,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.jonkykong.SideMenu;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
@@ -664,6 +667,7 @@
7B9DC90E1DC6E8C1000D4007 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0810"
LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
-283
View File
@@ -1,283 +0,0 @@
//
// SideMenuManager.swift
//
// Created by Jon Kent on 12/6/15.
// Copyright © 2015 Jon Kent. All rights reserved.
//
/* 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)
*/
open class SideMenuManager : NSObject {
@objc public enum MenuPresentMode : Int {
case menuSlideIn
case viewSlideOut
case viewSlideInOut
case menuDissolveIn
}
// Bounds which has been allocated for the app on the whole device screen
internal static var appScreenRect: CGRect {
let appWindowRect = UIApplication.shared.keyWindow?.bounds ?? UIWindow().bounds
return appWindowRect
}
/**
The presentation mode of the menu.
There are four modes in MenuPresentMode:
- menuSlideIn: Menu slides in over of the existing view.
- viewSlideOut: The existing view slides out to reveal the menu.
- viewSlideInOut: The existing view slides out while the menu slides in.
- 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
/// 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)
/// Duration of the animation when the menu is presented without gestures. Default is 0.35 seconds.
open static var menuAnimationPresentDuration = 0.35
/// Duration of the animation when the menu is dismissed without gestures. Default is 0.35 seconds.
open static var menuAnimationDismissDuration = 0.35
/// 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
/// The amount to scale the existing view controller or the menu view controller depending on the `menuPresentMode`. Default is 1 for no scaling. Less than 1 will shrink, greater than 1 will grow.
open static var menuAnimationTransformScaleFactor: CGFloat = 1
/// The background color behind menu animations. Depending on the animation settings this may not be visible. If `menuFadeStatusBar` is true, this color is used to fade it. Default is black.
open static var menuAnimationBackgroundColor: UIColor?
/// The shadow opacity around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is 0.5 for 50% opacity.
open static var menuShadowOpacity: Float = 0.5
/// The shadow color around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is black.
open static var menuShadowColor = UIColor.black
/// The radius of the shadow around the menu view controller or existing view controller depending on the `menuPresentMode`. Default is 5.
open static var menuShadowRadius: CGFloat = 5
/// The left menu swipe to dismiss gesture.
open static weak var menuLeftSwipeToDismissGesture: UIPanGestureRecognizer?
/// The right menu swipe to dismiss gesture.
open static weak var menuRightSwipeToDismissGesture: UIPanGestureRecognizer?
/// Enable or disable gestures that would swipe to present or dismiss the menu. Default is true.
open static var menuEnableSwipeGestures: Bool = true
/// Enable or disable interaction with the presenting view controller while the menu is displayed. Enabling may make it difficult to dismiss the menu or cause exceptions if the user tries to present and already presented menu. Default is false.
open static var menuPresentingViewControllerUserInteractionEnabled: Bool = false
/// The strength of the parallax effect on the existing view controller. Does not apply to `menuPresentMode` when set to `ViewSlideOut`. Default is 0.
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
/// -Warning: Deprecated. Use `menuAnimationTransformScaleFactor` instead.
@available(*, deprecated, renamed: "menuAnimationTransformScaleFactor")
open static var menuAnimationShrinkStrength: CGFloat {
get {
return menuAnimationTransformScaleFactor
}
set {
menuAnimationTransformScaleFactor = newValue
}
}
// prevent instantiation
fileprivate override init() {}
/**
The blur effect style of the menu if the menu's root view controller is a UITableViewController or UICollectionViewController.
- Note: If you want cells in a UITableViewController menu to show vibrancy, make them a subclass of UITableViewVibrantCell.
*/
open static var menuBlurEffectStyle: UIBlurEffectStyle? {
didSet {
if oldValue != menuBlurEffectStyle {
updateMenuBlurIfNecessary()
}
}
}
/// The left menu.
open static var menuLeftNavigationController: UISideMenuNavigationController? {
willSet {
if menuLeftNavigationController?.presentingViewController == nil {
removeMenuBlurForMenu(menuLeftNavigationController)
}
}
didSet {
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.
open static var menuRightNavigationController: UISideMenuNavigationController? {
willSet {
if menuRightNavigationController?.presentingViewController == nil {
removeMenuBlurForMenu(menuRightNavigationController)
}
}
didSet {
guard oldValue?.presentingViewController == nil else {
print("SideMenu Warning: menuRightNavigationController cannot be modified while it's presented.")
menuRightNavigationController = oldValue
return
}
setupNavigationController(menuRightNavigationController, leftSide: false)
}
}
fileprivate 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()
}
fileprivate class func updateMenuBlurIfNecessary() {
let menuBlurBlock = { (forMenu: UISideMenuNavigationController?) in
if let forMenu = forMenu {
setupMenuBlurForMenu(forMenu)
}
}
menuBlurBlock(menuLeftNavigationController)
menuBlurBlock(menuRightNavigationController)
}
fileprivate class func setupMenuBlurForMenu(_ forMenu: UISideMenuNavigationController?) {
removeMenuBlurForMenu(forMenu)
guard let forMenu = forMenu,
let menuBlurEffectStyle = menuBlurEffectStyle,
let view = forMenu.visibleViewController?.view
, !UIAccessibilityIsReduceTransparencyEnabled() else {
return
}
if forMenu.originalMenuBackgroundColor == nil {
forMenu.originalMenuBackgroundColor = view.backgroundColor
}
let blurEffect = UIBlurEffect(style: menuBlurEffectStyle)
let blurView = UIVisualEffectView(effect: blurEffect)
view.backgroundColor = UIColor.clear
if let tableViewController = forMenu.visibleViewController as? UITableViewController {
tableViewController.tableView.backgroundView = blurView
tableViewController.tableView.separatorEffect = UIVibrancyEffect(blurEffect: blurEffect)
tableViewController.tableView.reloadData()
} else {
blurView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
blurView.frame = view.bounds
view.insertSubview(blurView, at: 0)
}
}
fileprivate class func removeMenuBlurForMenu(_ forMenu: UISideMenuNavigationController?) {
guard let forMenu = forMenu,
let originalMenuBackgroundColor = forMenu.originalMenuBackgroundColor,
let 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 blurView = view.subviews[0] as? UIVisualEffectView {
blurView.removeFromSuperview()
}
}
/**
Adds screen edge gestures to a view to present a menu.
- 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] {
var array = [UIScreenEdgePanGestureRecognizer]()
if forMenu != .right {
let leftScreenEdgeGestureRecognizer = UIScreenEdgePanGestureRecognizer()
leftScreenEdgeGestureRecognizer.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handlePresentMenuLeftScreenEdge(_:)))
leftScreenEdgeGestureRecognizer.edges = .left
leftScreenEdgeGestureRecognizer.cancelsTouchesInView = true
toView.addGestureRecognizer(leftScreenEdgeGestureRecognizer)
array.append(leftScreenEdgeGestureRecognizer)
}
if forMenu != .left {
let rightScreenEdgeGestureRecognizer = UIScreenEdgePanGestureRecognizer()
rightScreenEdgeGestureRecognizer.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handlePresentMenuRightScreenEdge(_:)))
rightScreenEdgeGestureRecognizer.edges = .right
rightScreenEdgeGestureRecognizer.cancelsTouchesInView = true
toView.addGestureRecognizer(rightScreenEdgeGestureRecognizer)
array.append(rightScreenEdgeGestureRecognizer)
}
return array
}
/**
Adds a pan edge gesture to a view to present menus.
- Parameter toView: The view to add a pan gesture to.
- Returns: The pan gesture added to `toView`.
*/
@discardableResult open class func menuAddPanGestureToPresent(toView: UIView) -> UIPanGestureRecognizer {
let panGestureRecognizer = UIPanGestureRecognizer()
panGestureRecognizer.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handlePresentMenuPan(_:)))
toView.addGestureRecognizer(panGestureRecognizer)
return panGestureRecognizer
}
}
-460
View File
@@ -1,460 +0,0 @@
//
// SideMenuTransition.swift
// Pods
//
// Created by Jon Kent on 1/14/16.
//
//
import UIKit
open class SideMenuTransition: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
fileprivate var presenting = false
fileprivate var interactive = false
fileprivate static weak var originalSuperview: UIView?
fileprivate static var switchMenus = false
internal static let singleton = SideMenuTransition()
internal static var presentDirection: UIRectEdge = .left;
internal static weak var tapView: UIView?
internal static weak var statusBarView: UIView?
// prevent instantiation
fileprivate override init() {}
fileprivate class var viewControllerForPresentedMenu: UIViewController? {
get {
return SideMenuManager.menuLeftNavigationController?.presentingViewController != nil ? SideMenuManager.menuLeftNavigationController?.presentingViewController : SideMenuManager.menuRightNavigationController?.presentingViewController
}
}
fileprivate class var visibleViewController: UIViewController? {
get {
return getVisibleViewControllerFromViewController(UIApplication.shared.keyWindow?.rootViewController)
}
}
fileprivate class func getVisibleViewControllerFromViewController(_ viewController: UIViewController?) -> UIViewController? {
if let navigationController = viewController as? UINavigationController {
return getVisibleViewControllerFromViewController(navigationController.visibleViewController)
} else if let tabBarController = viewController as? UITabBarController {
return getVisibleViewControllerFromViewController(tabBarController.selectedViewController)
} else if let presentedViewController = viewController?.presentedViewController {
return getVisibleViewControllerFromViewController(presentedViewController)
}
return viewController
}
internal class func handlePresentMenuLeftScreenEdge(_ edge: UIScreenEdgePanGestureRecognizer) {
SideMenuTransition.presentDirection = .left
handlePresentMenuPan(edge)
}
internal class func handlePresentMenuRightScreenEdge(_ edge: UIScreenEdgePanGestureRecognizer) {
SideMenuTransition.presentDirection = .right
handlePresentMenuPan(edge)
}
internal class func handlePresentMenuPan(_ pan: UIPanGestureRecognizer) {
guard SideMenuManager.menuEnableSwipeGestures else {
return
}
// how much distance have we panned in reference to the parent view?
guard let view = viewControllerForPresentedMenu != nil ? viewControllerForPresentedMenu?.view : pan.view else {
return
}
let transform = view.transform
view.transform = CGAffineTransform.identity
let translation = pan.translation(in: pan.view!)
view.transform = transform
// do some math to translate this to a percentage based value
if !singleton.interactive {
if translation.x == 0 {
return // not sure which way the user is swiping yet, so do nothing
}
if !(pan is UIScreenEdgePanGestureRecognizer) {
SideMenuTransition.presentDirection = translation.x > 0 ? .left : .right
}
if let menuViewController = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController,
let visibleViewController = visibleViewController {
singleton.interactive = true
visibleViewController.present(menuViewController, animated: true, completion: nil)
}
}
let direction: CGFloat = SideMenuTransition.presentDirection == .left ? 1 : -1
let distance = translation.x / SideMenuManager.menuWidth
// now lets deal with different states that the gesture recognizer sends
switch (pan.state) {
case .began, .changed:
if pan is UIScreenEdgePanGestureRecognizer {
singleton.update(min(distance * direction, 1))
} else if distance > 0 && SideMenuTransition.presentDirection == .right && SideMenuManager.menuLeftNavigationController != nil {
SideMenuTransition.presentDirection = .left
switchMenus = true
singleton.cancel()
} else if distance < 0 && SideMenuTransition.presentDirection == .left && SideMenuManager.menuRightNavigationController != nil {
SideMenuTransition.presentDirection = .right
switchMenus = true
singleton.cancel()
} else {
singleton.update(min(distance * direction, 1))
}
default:
singleton.interactive = false
view.transform = CGAffineTransform.identity
let velocity = pan.velocity(in: pan.view!).x * direction
view.transform = transform
if velocity >= 100 || velocity >= -50 && abs(distance) >= 0.5 {
// bug workaround: animation briefly resets after call to finishInteractiveTransition() but before animateTransition completion is called.
if ProcessInfo().operatingSystemVersion.majorVersion == 8 && singleton.percentComplete > 1 - CGFloat(FLT_EPSILON) {
singleton.update(0.9999)
}
singleton.finish()
} else {
singleton.cancel()
}
}
}
internal class func handleHideMenuPan(_ pan: UIPanGestureRecognizer) {
if !SideMenuManager.menuEnableSwipeGestures {
return
}
let translation = pan.translation(in: pan.view!)
let direction:CGFloat = SideMenuTransition.presentDirection == .left ? -1 : 1
let distance = translation.x / SideMenuManager.menuWidth * direction
switch (pan.state) {
case .began:
singleton.interactive = true
viewControllerForPresentedMenu?.dismiss(animated: true, completion: nil)
case .changed:
singleton.update(max(min(distance, 1), 0))
default:
singleton.interactive = false
let velocity = pan.velocity(in: pan.view!).x * direction
if velocity >= 100 || velocity >= -50 && distance >= 0.5 {
// bug workaround: animation briefly resets after call to finishInteractiveTransition() but before animateTransition completion is called.
if ProcessInfo().operatingSystemVersion.majorVersion == 8 && singleton.percentComplete > 1 - CGFloat(FLT_EPSILON) {
singleton.update(0.9999)
}
singleton.finish()
} else {
singleton.cancel()
}
}
}
internal class func handleHideMenuTap(_ tap: UITapGestureRecognizer) {
viewControllerForPresentedMenu?.dismiss(animated: true, completion: nil)
}
internal class func hideMenuStart() {
NotificationCenter.default.removeObserver(SideMenuTransition.singleton)
guard let mainViewController = SideMenuTransition.viewControllerForPresentedMenu,
let menuView = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController?.view : SideMenuManager.menuRightNavigationController?.view else {return}
menuView.transform = CGAffineTransform.identity
mainViewController.view.transform = CGAffineTransform.identity
mainViewController.view.alpha = 1
SideMenuTransition.tapView?.frame = CGRect(x: 0, y: 0, width: mainViewController.view.frame.width, height: mainViewController.view.frame.height)
menuView.frame.origin.y = 0
menuView.frame.size.width = SideMenuManager.menuWidth
menuView.frame.size.height = mainViewController.view.frame.height
SideMenuTransition.statusBarView?.frame = UIApplication.shared.statusBarFrame
SideMenuTransition.statusBarView?.alpha = 0
switch SideMenuManager.menuPresentMode {
case .viewSlideOut:
menuView.alpha = 1 - SideMenuManager.menuAnimationFadeStrength
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? 0 : mainViewController.view.frame.width - SideMenuManager.menuWidth
mainViewController.view.frame.origin.x = 0
menuView.transform = CGAffineTransform(scaleX: SideMenuManager.menuAnimationTransformScaleFactor, y: SideMenuManager.menuAnimationTransformScaleFactor)
case .viewSlideInOut:
menuView.alpha = 1
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? -menuView.frame.width : mainViewController.view.frame.width
mainViewController.view.frame.origin.x = 0
case .menuSlideIn:
menuView.alpha = 1
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? -menuView.frame.width : mainViewController.view.frame.width
case .menuDissolveIn:
menuView.alpha = 0
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? 0 : mainViewController.view.frame.width - SideMenuManager.menuWidth
mainViewController.view.frame.origin.x = 0
}
}
internal class func hideMenuComplete() {
guard let mainViewController = SideMenuTransition.viewControllerForPresentedMenu,
let menuView = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController?.view : SideMenuManager.menuRightNavigationController?.view else {
return
}
SideMenuTransition.tapView?.removeFromSuperview()
SideMenuTransition.statusBarView?.removeFromSuperview()
mainViewController.view.motionEffects.removeAll()
mainViewController.view.layer.shadowOpacity = 0
menuView.layer.shadowOpacity = 0
if let topNavigationController = mainViewController as? UINavigationController {
topNavigationController.interactivePopGestureRecognizer!.isEnabled = true
}
originalSuperview?.addSubview(mainViewController.view)
}
internal class func presentMenuStart(forSize size: CGSize = SideMenuManager.appScreenRect.size) {
guard let menuView = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController?.view : SideMenuManager.menuRightNavigationController?.view,
let mainViewController = SideMenuTransition.viewControllerForPresentedMenu else {
return
}
menuView.transform = CGAffineTransform.identity
mainViewController.view.transform = CGAffineTransform.identity
menuView.frame.size.width = SideMenuManager.menuWidth
menuView.frame.size.height = size.height
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? 0 : size.width - SideMenuManager.menuWidth
SideMenuTransition.statusBarView?.frame = UIApplication.shared.statusBarFrame
SideMenuTransition.statusBarView?.alpha = 1
switch SideMenuManager.menuPresentMode {
case .viewSlideOut:
menuView.alpha = 1
let direction:CGFloat = SideMenuTransition.presentDirection == .left ? 1 : -1
mainViewController.view.frame.origin.x = direction * (menuView.frame.width)
mainViewController.view.layer.shadowColor = SideMenuManager.menuShadowColor.cgColor
mainViewController.view.layer.shadowRadius = SideMenuManager.menuShadowRadius
mainViewController.view.layer.shadowOpacity = SideMenuManager.menuShadowOpacity
mainViewController.view.layer.shadowOffset = CGSize(width: 0, height: 0)
case .viewSlideInOut:
menuView.alpha = 1
mainViewController.view.layer.shadowColor = SideMenuManager.menuShadowColor.cgColor
mainViewController.view.layer.shadowRadius = SideMenuManager.menuShadowRadius
mainViewController.view.layer.shadowOpacity = SideMenuManager.menuShadowOpacity
mainViewController.view.layer.shadowOffset = CGSize(width: 0, height: 0)
let direction:CGFloat = SideMenuTransition.presentDirection == .left ? 1 : -1
mainViewController.view.frame = CGRect(x: direction * (menuView.frame.width), y: 0, width: size.width, height: size.height)
mainViewController.view.transform = CGAffineTransform(scaleX: SideMenuManager.menuAnimationTransformScaleFactor, y: SideMenuManager.menuAnimationTransformScaleFactor)
mainViewController.view.alpha = 1 - SideMenuManager.menuAnimationFadeStrength
case .menuSlideIn, .menuDissolveIn:
menuView.alpha = 1
if SideMenuManager.menuBlurEffectStyle == nil {
menuView.layer.shadowColor = SideMenuManager.menuShadowColor.cgColor
menuView.layer.shadowRadius = SideMenuManager.menuShadowRadius
menuView.layer.shadowOpacity = SideMenuManager.menuShadowOpacity
menuView.layer.shadowOffset = CGSize(width: 0, height: 0)
}
mainViewController.view.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
mainViewController.view.transform = CGAffineTransform(scaleX: SideMenuManager.menuAnimationTransformScaleFactor, y: SideMenuManager.menuAnimationTransformScaleFactor)
mainViewController.view.alpha = 1 - SideMenuManager.menuAnimationFadeStrength
}
}
internal class func presentMenuComplete() {
NotificationCenter.default.addObserver(SideMenuTransition.singleton, selector:#selector(SideMenuTransition.applicationDidEnterBackgroundNotification), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
guard let mainViewController = SideMenuTransition.viewControllerForPresentedMenu else {
return
}
switch SideMenuManager.menuPresentMode {
case .menuSlideIn, .menuDissolveIn, .viewSlideInOut:
if SideMenuManager.menuParallaxStrength != 0 {
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = -SideMenuManager.menuParallaxStrength
horizontal.maximumRelativeValue = SideMenuManager.menuParallaxStrength
let vertical = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
vertical.minimumRelativeValue = -SideMenuManager.menuParallaxStrength
vertical.maximumRelativeValue = SideMenuManager.menuParallaxStrength
let group = UIMotionEffectGroup()
group.motionEffects = [horizontal, vertical]
mainViewController.view.addMotionEffect(group)
}
case .viewSlideOut: break;
}
if let topNavigationController = mainViewController as? UINavigationController {
topNavigationController.interactivePopGestureRecognizer!.isEnabled = false
}
}
// MARK: UIViewControllerAnimatedTransitioning protocol methods
// animate a change from one viewcontroller to another
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView
if let menuBackgroundColor = SideMenuManager.menuAnimationBackgroundColor {
container.backgroundColor = menuBackgroundColor
}
// create a tuple of our screens
let screens : (from:UIViewController, to:UIViewController) = (transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!, transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!)
// assign references to our menu view controller and the 'bottom' view controller from the tuple
// remember that our menuViewController will alternate between the from and to view controller depending if we're presenting or dismissing
let menuViewController = (!presenting ? screens.from : screens.to)
let topViewController = !presenting ? screens.to : screens.from
let menuView = menuViewController.view
let topView = topViewController.view
// prepare menu items to slide in
if presenting {
var tapView: UIView?
if !SideMenuManager.menuPresentingViewControllerUserInteractionEnabled {
tapView = UIView()
tapView!.autoresizingMask = [.flexibleHeight, .flexibleWidth]
let exitPanGesture = UIPanGestureRecognizer()
exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
let exitTapGesture = UITapGestureRecognizer()
exitTapGesture.addTarget(SideMenuTransition.self, action: #selector(SideMenuTransition.handleHideMenuTap(_:)))
tapView!.addGestureRecognizer(exitPanGesture)
tapView!.addGestureRecognizer(exitTapGesture)
SideMenuTransition.tapView = tapView
}
SideMenuTransition.originalSuperview = topView?.superview
// add the both views to our view controller
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
container.addSubview(menuView!)
container.addSubview(topView!)
if let tapView = tapView {
topView?.addSubview(tapView)
}
case .menuSlideIn, .menuDissolveIn:
container.addSubview(topView!)
if let tapView = tapView {
container.addSubview(tapView)
}
container.addSubview(menuView!)
}
if SideMenuManager.menuFadeStatusBar {
let blackBar = UIView()
if let menuShrinkBackgroundColor = SideMenuManager.menuAnimationBackgroundColor {
blackBar.backgroundColor = menuShrinkBackgroundColor
} else {
blackBar.backgroundColor = UIColor.black
}
blackBar.isUserInteractionEnabled = false
container.addSubview(blackBar)
SideMenuTransition.statusBarView = blackBar
}
SideMenuTransition.hideMenuStart() // offstage for interactive
}
// 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
if self.presenting {
SideMenuTransition.presentMenuStart() // onstage items: slide in
} else {
SideMenuTransition.hideMenuStart()
}
menuView?.isUserInteractionEnabled = false
}) { (finished) -> Void in
// tell our transitionContext object that we've finished animating
if transitionContext.transitionWasCancelled {
let viewControllerForPresentedMenu = SideMenuTransition.viewControllerForPresentedMenu
if self.presenting {
SideMenuTransition.hideMenuComplete()
} else {
SideMenuTransition.presentMenuComplete()
}
menuView?.isUserInteractionEnabled = true
transitionContext.completeTransition(false)
if SideMenuTransition.switchMenus {
SideMenuTransition.switchMenus = false
viewControllerForPresentedMenu?.present(SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController! : SideMenuManager.menuRightNavigationController!, animated: true, completion: nil)
}
return
}
if self.presenting {
SideMenuTransition.presentMenuComplete()
menuView?.isUserInteractionEnabled = true
transitionContext.completeTransition(true)
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
container.addSubview(topView!)
case .menuSlideIn, .menuDissolveIn:
container.insertSubview(topView!, at: 0)
}
if let statusBarView = SideMenuTransition.statusBarView {
container.bringSubview(toFront: statusBarView)
}
return
}
SideMenuTransition.hideMenuComplete()
transitionContext.completeTransition(true)
menuView?.removeFromSuperview()
}
}
// return how many seconds the transiton animation will take
open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return presenting ? SideMenuManager.menuAnimationPresentDuration : SideMenuManager.menuAnimationDismissDuration
}
// MARK: UIViewControllerTransitioningDelegate protocol methods
// return the animator when presenting a viewcontroller
// rememeber that an animator (or animation controller) is any object that aheres to the UIViewControllerAnimatedTransitioning protocol
open func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.presenting = true
SideMenuTransition.presentDirection = presented == SideMenuManager.menuLeftNavigationController ? .left : .right
return self
}
// return the animator used when dismissing from a viewcontroller
open func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
presenting = false
return self
}
open func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
// if our interactive flag is true, return the transition manager object
// otherwise return nil
return interactive ? SideMenuTransition.singleton : nil
}
open func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? SideMenuTransition.singleton : nil
}
internal func applicationDidEnterBackgroundNotification() {
if let menuViewController: UINavigationController = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController {
SideMenuTransition.hideMenuStart()
SideMenuTransition.hideMenuComplete()
menuViewController.dismiss(animated: false, completion: nil)
}
}
}
@@ -1,167 +0,0 @@
//
// UISideMenuNavigationController.swift
//
// Created by Jon Kent on 1/14/16.
// Copyright © 2016 Jon Kent. All rights reserved.
//
import UIKit
open class UISideMenuNavigationController: UINavigationController {
internal var originalMenuBackgroundColor: UIColor?
open override func awakeFromNib() {
super.awakeFromNib()
// if this isn't set here, segues cause viewWillAppear and viewDidAppear to be called twice
// likely because the transition completes and the presentingViewController is added back
// into view for the default transition style.
modalPresentationStyle = .overFullScreen
}
/// Whether the menu appears on the right or left side of the screen. Right is the default.
@IBInspectable open var leftSide:Bool = false {
didSet {
if isViewLoaded && oldValue != leftSide { // suppress warnings
didSetSide()
}
}
}
override open func viewDidLoad() {
super.viewDidLoad()
didSetSide()
}
fileprivate func didSetSide() {
if leftSide {
SideMenuManager.menuLeftNavigationController = self
} else {
SideMenuManager.menuRightNavigationController = self
}
}
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// we had presented a view before, so lets dismiss ourselves as already acted upon
if view.isHidden {
SideMenuTransition.hideMenuComplete()
dismiss(animated: false, completion: { () -> Void in
self.view.isHidden = false
})
}
}
override open func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// when presenting a view controller from the menu, the menu view gets moved into another transition view above our transition container
// which can break the visual layout we had before. So, we move the menu view back to its original transition view to preserve it.
if !isBeingDismissed {
if let mainView = presentingViewController?.view {
switch SideMenuManager.menuPresentMode {
case .viewSlideOut, .viewSlideInOut:
mainView.superview?.insertSubview(view, belowSubview: mainView)
case .menuSlideIn, .menuDissolveIn:
if let tapView = SideMenuTransition.tapView {
mainView.superview?.insertSubview(view, aboveSubview: tapView)
} else {
mainView.superview?.insertSubview(view, aboveSubview: mainView)
}
}
}
}
}
override open func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// we're presenting a view controller from the menu, so we need to hide the menu so it isn't g when the presented view is dismissed.
if !isBeingDismissed {
view.isHidden = true
SideMenuTransition.hideMenuStart()
}
}
override open func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// don't bother resizing if the view isn't visible
if view.isHidden {
return
}
SideMenuTransition.statusBarView?.isHidden = true
coordinator.animate(alongsideTransition: { (context) -> Void in
SideMenuTransition.presentMenuStart(forSize: size)
}) { (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)
}
}
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 super.shouldPerformSegue(withIdentifier: identifier, sender: sender)
}
override open func pushViewController(_ viewController: UIViewController, animated: Bool) {
guard viewControllers.count > 0 && !SideMenuManager.menuAllowSubmenus else {
// NOTE: pushViewController is called by init(rootViewController: UIViewController)
// so we must perform the normal super method in this case.
super.pushViewController(viewController, animated: true)
return
}
guard let presentingViewController = presentingViewController as? UINavigationController else {
print("SideMenu Warning: attempt to push a View Controller from \(self.presentingViewController.self) where its navigationController == nil. It must be embedded in a Navigation Controller for this to work.")
return
}
// to avoid overlapping dismiss & pop/push calls, create a transaction block where the menu
// is dismissed after showing the appropriate screen
CATransaction.begin()
CATransaction.setCompletionBlock( { () -> Void in
self.dismiss(animated: true, completion: nil)
self.visibleViewController?.viewWillAppear(false) // Hack: force selection to get cleared on UITableViewControllers when reappearing using custom transitions
})
UIView.animate(withDuration: SideMenuManager.menuAnimationDismissDuration, animations: { () -> Void in
SideMenuTransition.hideMenuStart()
})
if SideMenuManager.menuAllowPopIfPossible {
for subViewController in presentingViewController.viewControllers {
if type(of: subViewController) == type(of: viewController) {
presentingViewController.popToViewController(subViewController, animated: animated)
CATransaction.commit()
return
}
}
}
if let lastViewController = presentingViewController.viewControllers.last, SideMenuManager.menuAllowPushOfSameClassTwice {
if type(of: lastViewController) == type(of: viewController) {
CATransaction.commit()
return
}
}
presentingViewController.pushViewController(viewController, animated: animated)
CATransaction.commit()
}
}
-51
View File
@@ -1,51 +0,0 @@
//
// UITableViewVibrantCell.swift
// Pods
//
// Created by Jon Kent on 1/14/16.
//
//
import UIKit
open class UITableViewVibrantCell: UITableViewCell {
fileprivate var vibrancyView:UIVisualEffectView = UIVisualEffectView()
fileprivate var vibrancySelectedBackgroundView:UIVisualEffectView = UIVisualEffectView()
fileprivate var defaultSelectedBackgroundView:UIView?
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
vibrancyView.frame = bounds
vibrancyView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
for view in subviews {
vibrancyView.contentView.addSubview(view)
}
addSubview(vibrancyView)
let blurSelectionEffect = UIBlurEffect(style: .light)
vibrancySelectedBackgroundView.effect = blurSelectionEffect
defaultSelectedBackgroundView = selectedBackgroundView
}
override open func layoutSubviews() {
super.layoutSubviews()
// shouldn't be needed but backgroundColor is set to white on iPad:
backgroundColor = UIColor.clear
if !UIAccessibilityIsReduceTransparencyEnabled() && SideMenuManager.menuBlurEffectStyle != nil {
let blurEffect = UIBlurEffect(style: SideMenuManager.menuBlurEffectStyle!)
vibrancyView.effect = UIVibrancyEffect(blurEffect: blurEffect)
if selectedBackgroundView != nil && selectedBackgroundView != vibrancySelectedBackgroundView {
vibrancySelectedBackgroundView.contentView.addSubview(selectedBackgroundView!)
selectedBackgroundView = vibrancySelectedBackgroundView
}
} else {
vibrancyView.effect = nil
selectedBackgroundView = defaultSelectedBackgroundView
}
}
}