Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9f8fd7817 | |||
| dda720eee7 | |||
| 8bb2505b6f | |||
| 2878eea03f | |||
| 7512cb9373 | |||
| 189586d8e8 | |||
| f4d78af501 | |||
| af2ef21f88 | |||
| 25b87e4780 | |||
| c966675305 | |||
| b0dfba206c | |||
| 8960d3b4df | |||
| 05a117655b | |||
| 5ed24a978e | |||
| 330ea36ce5 | |||
| 05d934d084 | |||
| a520e98dbe | |||
| e49d564a2f | |||
| 632c35509b | |||
| b0a40b6fcf | |||
| 3d86c530ee | |||
| 4983a468c5 | |||
| bfbe4d21bf | |||
| 615ff0e391 | |||
| bdb9e4b3ae | |||
| 1c7d834c63 | |||
| 2e5ee04587 | |||
| 806a7dd1c7 | |||
| 094586042f | |||
| e919cd5b56 | |||
| e79169e735 | |||
| a43fbb64f8 | |||
| 275e01bdfd | |||
| 98da8fefc1 | |||
| b68fa60439 |
@@ -4,16 +4,20 @@ 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.
|
||||
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 do not have time to teach you**. I am only supporting bugfixes or reviewing pull requests.
|
||||
|
||||
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 provided 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, **saving _you_ the time it takes for me to personally respond.**
|
||||
|
||||
### If your question begins with _"How do I..."_
|
||||
- It's **not** a bug. Go back through the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md). Check out the [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example). Stay persistent, try a few different things, and you will figure it out! **It is generally faster for you to figure it out for yourself instead of waiting for me to respond to you.** I also recommend searching and posting your questions on [stackoverflow.com](stackoverflow.com). 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).
|
||||
- That's **not** a bug. Go back through the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md). Check out the [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example). Stay persistent, try a few different things, and you will figure it out! **It is generally faster for you to figure it out for yourself instead of waiting for me to respond to you.** I also recommend searching and posting your questions on [stackoverflow.com](stackoverflow.com). 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.
|
||||
### If your question begins with _"How 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 [join the proud members](https://github.com/jonkykong/SideMenu/graphs/contributors) who have contributed 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. I am not **tech support**. I am a **teacher**. However, if you think you found a bug, open an issue and I will respond to it when I find time. You must 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.
|
||||
### If your question is about SideMenu not working the way it's described in the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md)...
|
||||
- This *may* be a bug. You must be able to reproduce the bug in the [demo project](https://github.com/jonkykong/SideMenu/tree/master/Example) which has a minimal amount of code. This helps ensure you don't have a bug in your code unrelated to SideMenu. If the bug is reproducable, open an issue and I will respond to it when I find time.
|
||||
|
||||
**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 behave a specific way not described in the [README](https://github.com/jonkykong/SideMenu/blob/master/README.md). I am not **tech support**. I am not a **teacher**. If you open an issue while failing to follow these guidelines or use the provided templates your **request for help will be ignored**.
|
||||
|
||||
### Thanks again for your support and for being respectful of my time.
|
||||
I apologize if this seems harsh, but there have been too many developers that have willfully ignored all of this and continued to contact me.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
## New Issue Checklist
|
||||
<!--- Please complete all of the checks below before submitting a new issue (complete a check by marking it [x] with no spaces) -->
|
||||
I have read the [guidelines for contributing](https://github.com/jonkykong/SideMenu/blob/master/.github/CONTRIBUTING.md) and I understand:
|
||||
- [ ] My issue is happening in the **latest version** of SideMenu.
|
||||
- [ ] 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.
|
||||
|
||||
@@ -24,5 +24,26 @@ class SideMenuTableView: UITableViewController {
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.backgroundColor = UIColor.black.withAlphaComponent(0.2)
|
||||
tableView.backgroundView = imageView
|
||||
|
||||
print("SideMenu Appearing!")
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
print("SideMenu Appeared!")
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
print("SideMenu Disappearing!")
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
|
||||
print("SideMenu Disappeared!")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -97,12 +97,6 @@ open class SideMenuManager : NSObject {
|
||||
/// 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 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
|
||||
|
||||
@@ -221,6 +215,30 @@ open class SideMenuManager : NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// The left menu swipe to dismiss gesture.
|
||||
open static weak var menuLeftSwipeToDismissGesture: UIPanGestureRecognizer? {
|
||||
didSet {
|
||||
oldValue?.view?.removeGestureRecognizer(oldValue!)
|
||||
setupGesture(gesture: menuLeftSwipeToDismissGesture)
|
||||
}
|
||||
}
|
||||
|
||||
/// The right menu swipe to dismiss gesture.
|
||||
open static weak var menuRightSwipeToDismissGesture: UIPanGestureRecognizer? {
|
||||
didSet {
|
||||
oldValue?.view?.removeGestureRecognizer(oldValue!)
|
||||
setupGesture(gesture: menuRightSwipeToDismissGesture)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate class func setupGesture(gesture: UIPanGestureRecognizer?) {
|
||||
guard let gesture = gesture else {
|
||||
return
|
||||
}
|
||||
|
||||
gesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
|
||||
}
|
||||
|
||||
fileprivate class func setupNavigationController(_ forMenu: UISideMenuNavigationController?, leftSide: Bool) {
|
||||
guard let forMenu = forMenu else {
|
||||
return
|
||||
@@ -228,7 +246,6 @@ open class SideMenuManager : NSObject {
|
||||
|
||||
if menuEnableSwipeGestures {
|
||||
let exitPanGesture = UIPanGestureRecognizer()
|
||||
exitPanGesture.addTarget(SideMenuTransition.self, action:#selector(SideMenuTransition.handleHideMenuPan(_:)))
|
||||
forMenu.view.addGestureRecognizer(exitPanGesture)
|
||||
if leftSide {
|
||||
menuLeftSwipeToDismissGesture = exitPanGesture
|
||||
@@ -242,7 +259,7 @@ open class SideMenuManager : NSObject {
|
||||
updateMenuBlurIfNecessary()
|
||||
}
|
||||
|
||||
/// Enable or disable gestures that would swipe to present or dismiss the menu. Default is true.
|
||||
/// Enable or disable gestures that would swipe to dismiss the menu. Default is true.
|
||||
open static var menuEnableSwipeGestures: Bool = true {
|
||||
didSet {
|
||||
menuLeftSwipeToDismissGesture?.view?.removeGestureRecognizer(menuLeftSwipeToDismissGesture!)
|
||||
|
||||
@@ -17,7 +17,7 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
fileprivate static var switchMenus = false
|
||||
|
||||
internal static let singleton = SideMenuTransition()
|
||||
internal static var presentDirection: UIRectEdge = .left;
|
||||
internal static var presentDirection: UIRectEdge = .left
|
||||
internal static weak var tapView: UIView? {
|
||||
didSet {
|
||||
guard let tapView = tapView else {
|
||||
@@ -49,11 +49,25 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
}
|
||||
|
||||
// prevent instantiation
|
||||
fileprivate override init() {}
|
||||
fileprivate override init() {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector:#selector(SideMenuTransition.handleNotification), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector:#selector(SideMenuTransition.handleNotification), name: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil)
|
||||
}
|
||||
|
||||
fileprivate class var viewControllerForPresentedMenu: UIViewController? {
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(SideMenuTransition.singleton)
|
||||
}
|
||||
|
||||
fileprivate class var presentingViewControllerForMenu: UIViewController? {
|
||||
get {
|
||||
return SideMenuManager.menuLeftNavigationController?.presentingViewController != nil ? SideMenuManager.menuLeftNavigationController?.presentingViewController : SideMenuManager.menuRightNavigationController?.presentingViewController
|
||||
return SideMenuManager.menuLeftNavigationController?.presentingViewController ?? SideMenuManager.menuRightNavigationController?.presentingViewController
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate class var viewControllerForMenu: UISideMenuNavigationController? {
|
||||
get {
|
||||
return SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,12 +109,12 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
}
|
||||
|
||||
// how much distance have we panned in reference to the parent view?
|
||||
guard let view = viewControllerForPresentedMenu != nil ? viewControllerForPresentedMenu?.view : pan.view else {
|
||||
guard let view = presentingViewControllerForMenu?.view ?? pan.view else {
|
||||
return
|
||||
}
|
||||
|
||||
let transform = view.transform
|
||||
view.transform = CGAffineTransform.identity
|
||||
view.transform = .identity
|
||||
let translation = pan.translation(in: pan.view!)
|
||||
view.transform = transform
|
||||
|
||||
@@ -114,8 +128,7 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
SideMenuTransition.presentDirection = translation.x > 0 ? .left : .right
|
||||
}
|
||||
|
||||
if let menuViewController = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController,
|
||||
let visibleViewController = visibleViewController {
|
||||
if let menuViewController = viewControllerForMenu, let visibleViewController = visibleViewController {
|
||||
singleton.interactive = true
|
||||
visibleViewController.present(menuViewController, animated: true, completion: nil)
|
||||
} else {
|
||||
@@ -143,12 +156,12 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
}
|
||||
default:
|
||||
singleton.interactive = false
|
||||
view.transform = CGAffineTransform.identity
|
||||
view.transform = .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) {
|
||||
if ProcessInfo().operatingSystemVersion.majorVersion == 8 && singleton.percentComplete > 1 - CGFloat.ulpOfOne {
|
||||
singleton.update(0.9999)
|
||||
}
|
||||
singleton.finish()
|
||||
@@ -177,7 +190,7 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
|
||||
case .began:
|
||||
singleton.interactive = true
|
||||
viewControllerForPresentedMenu?.dismiss(animated: true, completion: nil)
|
||||
presentingViewControllerForMenu?.dismiss(animated: true, completion: nil)
|
||||
case .changed:
|
||||
singleton.update(max(min(distance, 1), 0))
|
||||
default:
|
||||
@@ -185,7 +198,7 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
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) {
|
||||
if ProcessInfo().operatingSystemVersion.majorVersion == 8 && singleton.percentComplete > 1 - CGFloat.ulpOfOne {
|
||||
singleton.update(0.9999)
|
||||
}
|
||||
singleton.finish()
|
||||
@@ -198,24 +211,30 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
}
|
||||
|
||||
internal class func handleHideMenuTap(_ tap: UITapGestureRecognizer) {
|
||||
viewControllerForPresentedMenu?.dismiss(animated: true, completion: nil)
|
||||
presentingViewControllerForMenu?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
internal class func hideMenuStart() {
|
||||
NotificationCenter.default.removeObserver(SideMenuTransition.singleton)
|
||||
guard let mainViewController = SideMenuTransition.viewControllerForPresentedMenu,
|
||||
guard let mainViewController = presentingViewControllerForMenu,
|
||||
let menuView = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController?.view : SideMenuManager.menuRightNavigationController?.view else {
|
||||
return
|
||||
}
|
||||
|
||||
menuView.transform = CGAffineTransform.identity
|
||||
mainViewController.view.transform = CGAffineTransform.identity
|
||||
mainViewController.view.transform = .identity
|
||||
mainViewController.view.alpha = 1
|
||||
SideMenuTransition.tapView?.frame = CGRect(x: 0, y: 0, width: mainViewController.view.frame.width, height: mainViewController.view.frame.height)
|
||||
mainViewController.view.frame.origin.y = 0
|
||||
menuView.transform = .identity
|
||||
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
|
||||
menuView.frame.size.height = mainViewController.view.frame.height // in case status bar height changed
|
||||
var statusBarFrame = UIApplication.shared.statusBarFrame
|
||||
let statusBarOffset = SideMenuManager.appScreenRect.size.height - mainViewController.view.frame.maxY
|
||||
// For in-call status bar, height is normally 40, which overlaps view. Instead, calculate height difference
|
||||
// of view and set height to fill in remaining space.
|
||||
if statusBarOffset >= CGFloat.ulpOfOne {
|
||||
statusBarFrame.size.height = statusBarOffset
|
||||
}
|
||||
SideMenuTransition.statusBarView?.frame = statusBarFrame
|
||||
SideMenuTransition.statusBarView?.alpha = 0
|
||||
|
||||
switch SideMenuManager.menuPresentMode {
|
||||
@@ -243,8 +262,8 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
}
|
||||
|
||||
internal class func hideMenuComplete() {
|
||||
guard let mainViewController = SideMenuTransition.viewControllerForPresentedMenu,
|
||||
let menuView = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController?.view : SideMenuManager.menuRightNavigationController?.view else {
|
||||
guard let mainViewController = presentingViewControllerForMenu,
|
||||
let menuView = viewControllerForMenu?.view else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -256,62 +275,71 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
if let topNavigationController = mainViewController as? UINavigationController {
|
||||
topNavigationController.interactivePopGestureRecognizer!.isEnabled = true
|
||||
}
|
||||
originalSuperview?.addSubview(mainViewController.view)
|
||||
if let originalSuperview = originalSuperview {
|
||||
originalSuperview.addSubview(mainViewController.view)
|
||||
let y = originalSuperview.bounds.height - mainViewController.view.frame.size.height
|
||||
mainViewController.view.frame.origin.y = max(y, 0)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
internal class func presentMenuStart() {
|
||||
guard let menuView = viewControllerForMenu?.view,
|
||||
let mainViewController = presentingViewControllerForMenu else {
|
||||
return
|
||||
}
|
||||
|
||||
menuView.transform = CGAffineTransform.identity
|
||||
mainViewController.view.transform = CGAffineTransform.identity
|
||||
menuView.alpha = 1
|
||||
menuView.transform = .identity
|
||||
menuView.frame.size.width = SideMenuManager.menuWidth
|
||||
menuView.frame.size.height = size.height
|
||||
let size = SideMenuManager.appScreenRect.size
|
||||
menuView.frame.origin.x = SideMenuTransition.presentDirection == .left ? 0 : size.width - SideMenuManager.menuWidth
|
||||
SideMenuTransition.statusBarView?.frame = UIApplication.shared.statusBarFrame
|
||||
mainViewController.view.transform = .identity
|
||||
mainViewController.view.frame.size.width = size.width
|
||||
let statusBarOffset = size.height - menuView.bounds.height
|
||||
mainViewController.view.bounds.size.height = size.height - max(statusBarOffset, 0)
|
||||
mainViewController.view.frame.origin.y = 0
|
||||
var statusBarFrame = UIApplication.shared.statusBarFrame
|
||||
// For in-call status bar, height is normally 40, which overlaps view. Instead, calculate height difference
|
||||
// of view and set height to fill in remaining space.
|
||||
if statusBarOffset >= CGFloat.ulpOfOne {
|
||||
statusBarFrame.size.height = statusBarOffset
|
||||
}
|
||||
SideMenuTransition.tapView?.transform = .identity
|
||||
SideMenuTransition.tapView?.bounds = mainViewController.view.bounds
|
||||
SideMenuTransition.statusBarView?.frame = statusBarFrame
|
||||
SideMenuTransition.statusBarView?.alpha = 1
|
||||
|
||||
switch SideMenuManager.menuPresentMode {
|
||||
|
||||
case .viewSlideOut:
|
||||
menuView.alpha = 1
|
||||
case .viewSlideOut, .viewSlideInOut:
|
||||
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.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.frame.origin.x = 0
|
||||
}
|
||||
|
||||
if SideMenuManager.menuPresentMode != .viewSlideOut {
|
||||
mainViewController.view.transform = CGAffineTransform(scaleX: SideMenuManager.menuAnimationTransformScaleFactor, y: SideMenuManager.menuAnimationTransformScaleFactor)
|
||||
if SideMenuManager.menuAnimationTransformScaleFactor > 1 {
|
||||
SideMenuTransition.tapView?.transform = mainViewController.view.transform
|
||||
}
|
||||
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 {
|
||||
guard let mainViewController = presentingViewControllerForMenu else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -337,6 +365,29 @@ open class SideMenuTransition: UIPercentDrivenInteractiveTransition {
|
||||
}
|
||||
}
|
||||
|
||||
internal func handleNotification() {
|
||||
guard let mainViewController = SideMenuTransition.presentingViewControllerForMenu,
|
||||
let menuViewController = SideMenuTransition.viewControllerForMenu,
|
||||
menuViewController.presentedViewController == nil && menuViewController.presentingViewController != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
if let originalSuperview = SideMenuTransition.originalSuperview {
|
||||
originalSuperview.addSubview(mainViewController.view)
|
||||
}
|
||||
UIView.animate(withDuration: SideMenuManager.menuAnimationDismissDuration,
|
||||
delay: 0,
|
||||
usingSpringWithDamping: SideMenuManager.menuAnimationUsingSpringWithDamping,
|
||||
initialSpringVelocity: SideMenuManager.menuAnimationInitialSpringVelocity,
|
||||
options: SideMenuManager.menuAnimationOptions,
|
||||
animations: {
|
||||
SideMenuTransition.hideMenuStart()
|
||||
}) { (finished) -> Void in
|
||||
SideMenuTransition.hideMenuComplete()
|
||||
menuViewController.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SideMenuTransition: UIViewControllerAnimatedTransitioning {
|
||||
@@ -400,7 +451,7 @@ extension SideMenuTransition: UIViewControllerAnimatedTransitioning {
|
||||
|
||||
// tell our transitionContext object that we've finished animating
|
||||
if transitionContext.transitionWasCancelled {
|
||||
let viewControllerForPresentedMenu = SideMenuTransition.viewControllerForPresentedMenu
|
||||
let viewControllerForPresentedMenu = SideMenuTransition.presentingViewControllerForMenu
|
||||
|
||||
if self.presenting {
|
||||
SideMenuTransition.hideMenuComplete()
|
||||
@@ -412,7 +463,7 @@ extension SideMenuTransition: UIViewControllerAnimatedTransitioning {
|
||||
|
||||
if SideMenuTransition.switchMenus {
|
||||
SideMenuTransition.switchMenus = false
|
||||
viewControllerForPresentedMenu?.present(SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController! : SideMenuManager.menuRightNavigationController!, animated: true, completion: nil)
|
||||
viewControllerForPresentedMenu?.present(SideMenuTransition.viewControllerForMenu!, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -420,12 +471,6 @@ extension SideMenuTransition: UIViewControllerAnimatedTransitioning {
|
||||
|
||||
if self.presenting {
|
||||
SideMenuTransition.presentMenuComplete()
|
||||
if !SideMenuManager.menuPresentingViewControllerUserInteractionEnabled {
|
||||
let tapView = UIView()
|
||||
topView.addSubview(tapView)
|
||||
tapView.frame = topView.bounds
|
||||
SideMenuTransition.tapView = tapView
|
||||
}
|
||||
transitionContext.completeTransition(true)
|
||||
switch SideMenuManager.menuPresentMode {
|
||||
case .viewSlideOut, .viewSlideInOut:
|
||||
@@ -433,6 +478,16 @@ extension SideMenuTransition: UIViewControllerAnimatedTransitioning {
|
||||
case .menuSlideIn, .menuDissolveIn:
|
||||
container.insertSubview(topView, at: 0)
|
||||
}
|
||||
if !SideMenuManager.menuPresentingViewControllerUserInteractionEnabled {
|
||||
let tapView = UIView()
|
||||
container.insertSubview(tapView, aboveSubview: topView)
|
||||
tapView.bounds = container.bounds
|
||||
tapView.center = topView.center
|
||||
if SideMenuManager.menuAnimationTransformScaleFactor > 1 {
|
||||
tapView.transform = topView.transform
|
||||
}
|
||||
SideMenuTransition.tapView = tapView
|
||||
}
|
||||
if let statusBarView = SideMenuTransition.statusBarView {
|
||||
container.bringSubview(toFront: statusBarView)
|
||||
}
|
||||
@@ -506,13 +561,4 @@ extension SideMenuTransition: UIViewControllerTransitioningDelegate {
|
||||
return interactive ? SideMenuTransition.singleton : nil
|
||||
}
|
||||
|
||||
internal func applicationDidEnterBackgroundNotification() {
|
||||
if let menuViewController: UINavigationController = SideMenuTransition.presentDirection == .left ? SideMenuManager.menuLeftNavigationController : SideMenuManager.menuRightNavigationController,
|
||||
menuViewController.presentedViewController == nil {
|
||||
SideMenuTransition.hideMenuStart()
|
||||
SideMenuTransition.hideMenuComplete()
|
||||
menuViewController.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,13 @@ open class UISideMenuNavigationController: UINavigationController {
|
||||
didSetSide()
|
||||
}
|
||||
|
||||
open override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
// Dismiss keyboard to prevent weird keyboard animations from occurring during transition
|
||||
presentingViewController?.view.endEditing(true)
|
||||
}
|
||||
|
||||
fileprivate func didSetSide() {
|
||||
if leftSide {
|
||||
SideMenuManager.menuLeftNavigationController = self
|
||||
@@ -46,7 +53,7 @@ open class UISideMenuNavigationController: UINavigationController {
|
||||
override open func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
// we had presented a view before, so lets dismiss ourselves as already acted upon
|
||||
// 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
|
||||
@@ -83,7 +90,7 @@ open class UISideMenuNavigationController: UINavigationController {
|
||||
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.
|
||||
// We're presenting a view controller from the menu, so we need to hide the menu so it isn't showing when the presented view is dismissed.
|
||||
if !isBeingDismissed {
|
||||
view.isHidden = true
|
||||
SideMenuTransition.hideMenuStart()
|
||||
@@ -93,30 +100,28 @@ open class UISideMenuNavigationController: UINavigationController {
|
||||
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 {
|
||||
// Don't bother resizing if the view isn't visible
|
||||
guard !view.isHidden else {
|
||||
return
|
||||
}
|
||||
|
||||
SideMenuTransition.statusBarView?.isHidden = true
|
||||
coordinator.animate(alongsideTransition: { (context) -> Void in
|
||||
SideMenuTransition.presentMenuStart(forSize: size)
|
||||
}) { (context) -> Void in
|
||||
SideMenuTransition.statusBarView?.isHidden = false
|
||||
NotificationCenter.default.removeObserver(SideMenuTransition.singleton, name: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil)
|
||||
coordinator.animate(alongsideTransition: { (context) in
|
||||
SideMenuTransition.presentMenuStart()
|
||||
}) { (context) in
|
||||
NotificationCenter.default.addObserver(SideMenuTransition.singleton, selector:#selector(SideMenuTransition.handleNotification), name: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if let presentingViewController = presentingViewController {
|
||||
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)
|
||||
if let presentingViewController = presentingViewController {
|
||||
return presentingViewController.shouldPerformSegue(withIdentifier: identifier, sender: sender)
|
||||
}
|
||||
|
||||
return super.shouldPerformSegue(withIdentifier: identifier, sender: sender)
|
||||
@@ -132,11 +137,11 @@ open class UISideMenuNavigationController: UINavigationController {
|
||||
|
||||
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.")
|
||||
print("SideMenu Warning: attempt to push a View Controller from \(String(describing: 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
|
||||
// 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
|
||||
@@ -192,6 +197,7 @@ open class UISideMenuNavigationController: UINavigationController {
|
||||
navigationController.pushViewController(viewController, animated: animated)
|
||||
CATransaction.commit()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,19 +5,24 @@
|
||||
[](http://cocoapods.org/pods/SideMenu)
|
||||
|
||||
### If you like SideMenu, give it a ★ at the top right of its [GitHub](https://github.com/jonkykong/SideMenu) page.
|
||||
#### Using SideMenu in your app? [Send](mailto:contact@jonkent.me?subject=SideMenu in action!) me a link to your app in the app store!
|
||||
#### Using SideMenu in your app? [Send](mailto:contact@jonkent.me?subject=SideMenu+in+action!) me a link to your app in the app store!
|
||||
|
||||
> I'm Jon Kent and I freelance iOS design, development, and mobile strategies. I love coffee and play the drums. [**Hire me**](mailto:contact@jonkent.me?subject=Let's build something amazing.) to help you make cool stuff. I also have a [website](http://jonkent.me). *Note: If you're having a problem with SideMenu, please open an [issue](https://github.com/jonkykong/SideMenu/issues/new) and do not email me.*
|
||||
> I'm Jon Kent and I freelance iOS design, development, and mobile strategies. I love coffee and play the drums.
|
||||
> * [**Hire me**](mailto:contact@jonkent.me?subject=Let's+build+something+amazing) to help you make cool stuff. *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.*
|
||||
> * [Website](http://jonkent.me).
|
||||
> * Building and maintaining this free library takes time. Help keep me awake and buy me a coffee ☕️ via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=contact%40jonkent%2eme&lc=US¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted).
|
||||
|
||||
## Overview
|
||||
|
||||
SideMenu is a simple and versatile side menu control written in Swift.
|
||||
* **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).
|
||||
* Four standard animation styles to choose from (there's even a parallax effect 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.
|
||||
* Menus can be presented and dismissed the same as any other view controller since this control uses [custom transitions](https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html).
|
||||
* Animations use your view controllers, not snapshots.
|
||||
* Properly handles screen rotation and in-call status bar height changes.
|
||||
|
||||
Check out the example project to see it in action!
|
||||
### Preview Samples
|
||||
@@ -46,7 +51,7 @@ use_frameworks!
|
||||
|
||||
pod 'SideMenu'
|
||||
|
||||
# For Swift 2.3, use:
|
||||
# For Swift 2.3 (no longer maintained), use:
|
||||
# pod 'SideMenu', '~> 1.2.1'
|
||||
```
|
||||
|
||||
@@ -75,13 +80,13 @@ github "jonkykong/SideMenu" "master"
|
||||
|
||||
## Usage
|
||||
### Code-less Storyboard Implementation
|
||||
1. Create a Navigation Controller for a side menu. Set the custom class of the Navigation Controller to be `UISideMenuNavigationController` in the **Identity Inspector**. Create a Root View Controller for the Navigation Controller (shown as a UITableViewController below). Set up any Triggered Segues you want in that View Controller.
|
||||
1. Create a Navigation Controller for a side menu. Set the `Custom Class` of the Navigation Controller to be `UISideMenuNavigationController` in the **Identity Inspector**. Set the `Module` to `SideMenu` (ignore this step if you've manually added SideMenu to your project). Create a Root View Controller for the Navigation Controller (shown as a UITableViewController below). Set up any Triggered Segues you want in that view controller.
|
||||

|
||||
|
||||
2. Set the `Left Side` property of the `UISideMenuNavigationController` to On if you want it to appear from the left side of the screen, or Off/Default if you want it to appear from the right side.
|
||||

|
||||
|
||||
3. Add a UIButton or UIBarButton to a View Controller that you want to display the menu from. Set that button's Triggered Segues action to modally present the Navigation Controller from step 1.
|
||||
3. Add a UIButton or UIBarButton to a view controller that you want to display the menu from. Set that button's Triggered Segues action to modally present the Navigation Controller from step 1.
|
||||

|
||||
|
||||
That's it. *Note: you can only enable gestures in code.*
|
||||
@@ -91,24 +96,24 @@ First:
|
||||
import SideMenu
|
||||
```
|
||||
|
||||
In your View Controller's `viewDidLoad` event, do something like this:
|
||||
In your view controller's `viewDidLoad` event, do something like this (**IMPORTANT: If you're seeing a black menu when you use gestures, read this section carefully!**):
|
||||
``` swift
|
||||
// Define the menus
|
||||
let menuLeftNavigationController = UISideMenuNavigationController()
|
||||
let menuLeftNavigationController = UISideMenuNavigationController(rootViewController: YourViewController)
|
||||
menuLeftNavigationController.leftSide = true
|
||||
// UISideMenuNavigationController is a subclass of UINavigationController, so do any additional configuration
|
||||
// of it here like setting its viewControllers. If you're using storyboards, you'll want to do something like:
|
||||
// let menuLeftNavigationController = storyboard!.instantiateViewController(withIdentifier: "LeftMenuNavigationController") as! UISideMenuNavigationController
|
||||
SideMenuManager.menuLeftNavigationController = menuLeftNavigationController
|
||||
|
||||
let menuRightNavigationController = UISideMenuNavigationController()
|
||||
let menuRightNavigationController = UISideMenuNavigationController(rootViewController: YourViewController)
|
||||
// UISideMenuNavigationController is a subclass of UINavigationController, so do any additional configuration
|
||||
// of it here like setting its viewControllers. If you're using storyboards, you'll want to do something like:
|
||||
// let menuRightNavigationController = storyboard!.instantiateViewController(withIdentifier: "RightMenuNavigationController") as! UISideMenuNavigationController
|
||||
SideMenuManager.menuRightNavigationController = menuRightNavigationController
|
||||
|
||||
// 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!
|
||||
// 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)
|
||||
```
|
||||
@@ -119,7 +124,7 @@ present(SideMenuManager.menuLeftNavigationController!, animated: true, completio
|
||||
// Similarly, to dismiss a menu programmatically, you would do this:
|
||||
dismiss(animated: true, completion: nil)
|
||||
|
||||
// For Swift 2.3, use:
|
||||
// For Swift 2.3 (no longer maintained), use:
|
||||
// presentViewController(SideMenuManager.menuLeftNavigationController!, animated: true, completion: nil)
|
||||
```
|
||||
That's it.
|
||||
@@ -186,7 +191,7 @@ 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.
|
||||
/// Enable or disable gestures that would swipe to 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.
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "SideMenu"
|
||||
s.version = "2.2.0"
|
||||
s.version = "2.3.1"
|
||||
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.
|
||||
|
||||
@@ -279,7 +279,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0800;
|
||||
LastUpgradeCheck = 0820;
|
||||
LastUpgradeCheck = 0830;
|
||||
ORGANIZATIONNAME = jonkykong;
|
||||
TargetAttributes = {
|
||||
7B48A0D21DCB2487002990A1 = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
LastUpgradeVersion = "0830"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
Reference in New Issue
Block a user