|
|
@@ -0,0 +1,1051 @@
|
|
|
+//
|
|
|
+// SlideMenuController.swift
|
|
|
+// Gasteizko Margolariak
|
|
|
+//
|
|
|
+// Created by Inigo Valentin on 2016-08-23
|
|
|
+// Copyright © 2016 Inigo Valentin. All rights reserved.
|
|
|
+//
|
|
|
+// Based on the work of Yuji Hato.
|
|
|
+//
|
|
|
+
|
|
|
+import Foundation
|
|
|
+import UIKit
|
|
|
+
|
|
|
+@objc public protocol SlideMenuControllerDelegate {
|
|
|
+ optional func leftWillOpen()
|
|
|
+ optional func leftDidOpen()
|
|
|
+ optional func leftWillClose()
|
|
|
+ optional func leftDidClose()
|
|
|
+ optional func rightWillOpen()
|
|
|
+ optional func rightDidOpen()
|
|
|
+ optional func rightWillClose()
|
|
|
+ optional func rightDidClose()
|
|
|
+}
|
|
|
+
|
|
|
+public struct SlideMenuOptions {
|
|
|
+ public static var leftViewWidth: CGFloat = 270.0
|
|
|
+ public static var leftBezelWidth: CGFloat? = 16.0
|
|
|
+ public static var contentViewScale: CGFloat = 0.96
|
|
|
+ public static var contentViewOpacity: CGFloat = 0.5
|
|
|
+ public static var contentViewDrag: Bool = false
|
|
|
+ public static var shadowOpacity: CGFloat = 0.0
|
|
|
+ public static var shadowRadius: CGFloat = 0.0
|
|
|
+ public static var shadowOffset: CGSize = CGSizeMake(0,0)
|
|
|
+ public static var panFromBezel: Bool = true
|
|
|
+ public static var animationDuration: CGFloat = 0.4
|
|
|
+ public static var rightViewWidth: CGFloat = 270.0
|
|
|
+ public static var rightBezelWidth: CGFloat? = 16.0
|
|
|
+ public static var rightPanFromBezel: Bool = true
|
|
|
+ public static var hideStatusBar: Bool = true
|
|
|
+ public static var pointOfNoReturnWidth: CGFloat = 44.0
|
|
|
+ public static var simultaneousGestureRecognizers: Bool = true
|
|
|
+ public static var opacityViewBackgroundColor: UIColor = UIColor.blackColor()
|
|
|
+}
|
|
|
+
|
|
|
+public class SlideMenuController: UIViewController, UIGestureRecognizerDelegate {
|
|
|
+
|
|
|
+
|
|
|
+ public enum SlideAction {
|
|
|
+ case Open
|
|
|
+ case Close
|
|
|
+ }
|
|
|
+
|
|
|
+ public enum TrackAction {
|
|
|
+ case LeftTapOpen
|
|
|
+ case LeftTapClose
|
|
|
+ case LeftFlickOpen
|
|
|
+ case LeftFlickClose
|
|
|
+ case RightTapOpen
|
|
|
+ case RightTapClose
|
|
|
+ case RightFlickOpen
|
|
|
+ case RightFlickClose
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ struct PanInfo {
|
|
|
+ var action: SlideAction
|
|
|
+ var shouldBounce: Bool
|
|
|
+ var velocity: CGFloat
|
|
|
+ }
|
|
|
+
|
|
|
+ public weak var delegate: SlideMenuControllerDelegate?
|
|
|
+
|
|
|
+ public var opacityView = UIView()
|
|
|
+ public var mainContainerView = UIView()
|
|
|
+ public var leftContainerView = UIView()
|
|
|
+ public var rightContainerView = UIView()
|
|
|
+ public var mainViewController: UIViewController?
|
|
|
+ public var leftViewController: UIViewController?
|
|
|
+ public var leftPanGesture: UIPanGestureRecognizer?
|
|
|
+ public var leftTapGesture: UITapGestureRecognizer?
|
|
|
+ public var rightViewController: UIViewController?
|
|
|
+ public var rightPanGesture: UIPanGestureRecognizer?
|
|
|
+ public var rightTapGesture: UITapGestureRecognizer?
|
|
|
+
|
|
|
+ public required init?(coder aDecoder: NSCoder) {
|
|
|
+ super.init(coder: aDecoder)
|
|
|
+ }
|
|
|
+
|
|
|
+ public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
|
|
|
+ super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
|
|
|
+ }
|
|
|
+
|
|
|
+ public convenience init(mainViewController: UIViewController, leftMenuViewController: UIViewController) {
|
|
|
+ self.init()
|
|
|
+ self.mainViewController = mainViewController
|
|
|
+ leftViewController = leftMenuViewController
|
|
|
+ initView()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public convenience init(mainViewController: UIViewController, leftMenuViewController: UIViewController, rightMenuViewController: UIViewController) {
|
|
|
+ self.init()
|
|
|
+ self.mainViewController = mainViewController
|
|
|
+ leftViewController = leftMenuViewController
|
|
|
+ initView()
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func awakeFromNib() {
|
|
|
+ initView()
|
|
|
+ }
|
|
|
+
|
|
|
+ deinit { }
|
|
|
+
|
|
|
+ public func initView() {
|
|
|
+ mainContainerView = UIView(frame: view.bounds)
|
|
|
+ mainContainerView.backgroundColor = UIColor.clearColor()
|
|
|
+ mainContainerView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
|
|
|
+ view.insertSubview(mainContainerView, atIndex: 0)
|
|
|
+
|
|
|
+ var opacityframe: CGRect = view.bounds
|
|
|
+ let opacityOffset: CGFloat = 0
|
|
|
+ opacityframe.origin.y = opacityframe.origin.y + opacityOffset
|
|
|
+ opacityframe.size.height = opacityframe.size.height - opacityOffset
|
|
|
+ opacityView = UIView(frame: opacityframe)
|
|
|
+ opacityView.backgroundColor = SlideMenuOptions.opacityViewBackgroundColor
|
|
|
+ opacityView.autoresizingMask = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth]
|
|
|
+ opacityView.layer.opacity = 0.0
|
|
|
+ view.insertSubview(opacityView, atIndex: 1)
|
|
|
+
|
|
|
+ if leftViewController != nil {
|
|
|
+ var leftFrame: CGRect = view.bounds
|
|
|
+ leftFrame.size.width = SlideMenuOptions.leftViewWidth
|
|
|
+ leftFrame.origin.x = leftMinOrigin();
|
|
|
+ let leftOffset: CGFloat = 0
|
|
|
+ leftFrame.origin.y = leftFrame.origin.y + leftOffset
|
|
|
+ leftFrame.size.height = leftFrame.size.height - leftOffset
|
|
|
+ leftContainerView = UIView(frame: leftFrame)
|
|
|
+ leftContainerView.backgroundColor = UIColor.clearColor()
|
|
|
+ leftContainerView.autoresizingMask = UIViewAutoresizing.FlexibleHeight
|
|
|
+ view.insertSubview(leftContainerView, atIndex: 2)
|
|
|
+ addLeftGestures()
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
|
|
+ super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
|
|
|
+ mainContainerView.transform = CGAffineTransformMakeScale(1.0, 1.0)
|
|
|
+ leftContainerView.hidden = true
|
|
|
+ rightContainerView.hidden = true
|
|
|
+
|
|
|
+ coordinator.animateAlongsideTransition(nil, completion: { (context: UIViewControllerTransitionCoordinatorContext!) -> Void in
|
|
|
+ self.closeLeftNonAnimation()
|
|
|
+ self.closeRightNonAnimation()
|
|
|
+ self.leftContainerView.hidden = false
|
|
|
+ self.rightContainerView.hidden = false
|
|
|
+
|
|
|
+ if self.leftPanGesture != nil && self.leftPanGesture != nil {
|
|
|
+ self.removeLeftGestures()
|
|
|
+ self.addLeftGestures()
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.rightPanGesture != nil && self.rightPanGesture != nil {
|
|
|
+ self.removeRightGestures()
|
|
|
+ self.addRightGestures()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func viewDidLoad() {
|
|
|
+ super.viewDidLoad()
|
|
|
+ edgesForExtendedLayout = UIRectEdge.None
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
|
|
|
+ if let mainController = self.mainViewController{
|
|
|
+ return mainController.supportedInterfaceOrientations()
|
|
|
+ }
|
|
|
+ return UIInterfaceOrientationMask.All
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func shouldAutorotate() -> Bool {
|
|
|
+ return mainViewController?.shouldAutorotate() ?? false
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func viewWillLayoutSubviews() {
|
|
|
+ // topLayoutGuideの値が確定するこのタイミングで各種ViewControllerをセットする
|
|
|
+ setUpViewController(mainContainerView, targetViewController: mainViewController)
|
|
|
+ setUpViewController(leftContainerView, targetViewController: leftViewController)
|
|
|
+ setUpViewController(rightContainerView, targetViewController: rightViewController)
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func openLeft() {
|
|
|
+ guard let _ = leftViewController else { // If leftViewController is nil, then return
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ self.delegate?.leftWillOpen?()
|
|
|
+
|
|
|
+ setOpenWindowLevel()
|
|
|
+ // for call viewWillAppear of leftViewController
|
|
|
+ leftViewController?.beginAppearanceTransition(isLeftHidden(), animated: true)
|
|
|
+ openLeftWithVelocity(0.0)
|
|
|
+
|
|
|
+ track(.LeftTapOpen)
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func openRight() {
|
|
|
+ guard let _ = rightViewController else { // If rightViewController is nil, then return
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ self.delegate?.rightWillOpen?()
|
|
|
+
|
|
|
+ setOpenWindowLevel()
|
|
|
+ rightViewController?.beginAppearanceTransition(isRightHidden(), animated: true)
|
|
|
+ openRightWithVelocity(0.0)
|
|
|
+
|
|
|
+ track(.RightTapOpen)
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func closeLeft() {
|
|
|
+ guard let _ = leftViewController else { // If leftViewController is nil, then return
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ self.delegate?.leftWillClose?()
|
|
|
+
|
|
|
+ leftViewController?.beginAppearanceTransition(isLeftHidden(), animated: true)
|
|
|
+ closeLeftWithVelocity(0.0)
|
|
|
+ setCloseWindowLevel()
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func closeRight() {
|
|
|
+ guard let _ = rightViewController else { // If rightViewController is nil, then return
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ self.delegate?.rightWillClose?()
|
|
|
+
|
|
|
+ rightViewController?.beginAppearanceTransition(isRightHidden(), animated: true)
|
|
|
+ closeRightWithVelocity(0.0)
|
|
|
+ setCloseWindowLevel()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public func addLeftGestures() {
|
|
|
+
|
|
|
+ if (leftViewController != nil) {
|
|
|
+ if leftPanGesture == nil {
|
|
|
+ leftPanGesture = UIPanGestureRecognizer(target: self, action: #selector(self.handleLeftPanGesture(_:)))
|
|
|
+ leftPanGesture!.delegate = self
|
|
|
+ view.addGestureRecognizer(leftPanGesture!)
|
|
|
+ }
|
|
|
+
|
|
|
+ if leftTapGesture == nil {
|
|
|
+ leftTapGesture = UITapGestureRecognizer(target: self, action: #selector(self.toggleLeft))
|
|
|
+ leftTapGesture!.delegate = self
|
|
|
+ view.addGestureRecognizer(leftTapGesture!)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func addRightGestures() {
|
|
|
+
|
|
|
+ if (rightViewController != nil) {
|
|
|
+ if rightPanGesture == nil {
|
|
|
+ rightPanGesture = UIPanGestureRecognizer(target: self, action: #selector(self.handleRightPanGesture(_:)))
|
|
|
+ rightPanGesture!.delegate = self
|
|
|
+ view.addGestureRecognizer(rightPanGesture!)
|
|
|
+ }
|
|
|
+
|
|
|
+ if rightTapGesture == nil {
|
|
|
+ rightTapGesture = UITapGestureRecognizer(target: self, action: #selector(self.toggleRight))
|
|
|
+ rightTapGesture!.delegate = self
|
|
|
+ view.addGestureRecognizer(rightTapGesture!)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func removeLeftGestures() {
|
|
|
+
|
|
|
+ if leftPanGesture != nil {
|
|
|
+ view.removeGestureRecognizer(leftPanGesture!)
|
|
|
+ leftPanGesture = nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if leftTapGesture != nil {
|
|
|
+ view.removeGestureRecognizer(leftTapGesture!)
|
|
|
+ leftTapGesture = nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func removeRightGestures() {
|
|
|
+
|
|
|
+ if rightPanGesture != nil {
|
|
|
+ view.removeGestureRecognizer(rightPanGesture!)
|
|
|
+ rightPanGesture = nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if rightTapGesture != nil {
|
|
|
+ view.removeGestureRecognizer(rightTapGesture!)
|
|
|
+ rightTapGesture = nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func isTagetViewController() -> Bool {
|
|
|
+ // Function to determine the target ViewController
|
|
|
+ // Please to override it if necessary
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ public func track(trackAction: TrackAction) {
|
|
|
+ // function is for tracking
|
|
|
+ // Please to override it if necessary
|
|
|
+ }
|
|
|
+
|
|
|
+ struct LeftPanState {
|
|
|
+ static var frameAtStartOfPan: CGRect = CGRectZero
|
|
|
+ static var startPointOfPan: CGPoint = CGPointZero
|
|
|
+ static var wasOpenAtStartOfPan: Bool = false
|
|
|
+ static var wasHiddenAtStartOfPan: Bool = false
|
|
|
+ static var lastState : UIGestureRecognizerState = .Ended
|
|
|
+ }
|
|
|
+
|
|
|
+ func handleLeftPanGesture(panGesture: UIPanGestureRecognizer) {
|
|
|
+
|
|
|
+ if !isTagetViewController() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if isRightOpen() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ switch panGesture.state {
|
|
|
+ case UIGestureRecognizerState.Began:
|
|
|
+ if LeftPanState.lastState != .Ended && LeftPanState.lastState != .Cancelled && LeftPanState.lastState != .Failed {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if isLeftHidden() {
|
|
|
+ self.delegate?.leftWillOpen?()
|
|
|
+ } else {
|
|
|
+ self.delegate?.leftWillClose?()
|
|
|
+ }
|
|
|
+
|
|
|
+ LeftPanState.frameAtStartOfPan = leftContainerView.frame
|
|
|
+ LeftPanState.startPointOfPan = panGesture.locationInView(view)
|
|
|
+ LeftPanState.wasOpenAtStartOfPan = isLeftOpen()
|
|
|
+ LeftPanState.wasHiddenAtStartOfPan = isLeftHidden()
|
|
|
+
|
|
|
+ leftViewController?.beginAppearanceTransition(LeftPanState.wasHiddenAtStartOfPan, animated: true)
|
|
|
+ addShadowToView(leftContainerView)
|
|
|
+ setOpenWindowLevel()
|
|
|
+ case UIGestureRecognizerState.Changed:
|
|
|
+ if LeftPanState.lastState != .Began && LeftPanState.lastState != .Changed {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let translation: CGPoint = panGesture.translationInView(panGesture.view!)
|
|
|
+ leftContainerView.frame = applyLeftTranslation(translation, toFrame: LeftPanState.frameAtStartOfPan)
|
|
|
+ applyLeftOpacity()
|
|
|
+ applyLeftContentViewScale()
|
|
|
+ case UIGestureRecognizerState.Ended, UIGestureRecognizerState.Cancelled:
|
|
|
+ if LeftPanState.lastState != .Changed {
|
|
|
+ setCloseWindowLevel()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let velocity:CGPoint = panGesture.velocityInView(panGesture.view)
|
|
|
+ let panInfo: PanInfo = panLeftResultInfoForVelocity(velocity)
|
|
|
+
|
|
|
+ if panInfo.action == .Open {
|
|
|
+ if !LeftPanState.wasHiddenAtStartOfPan {
|
|
|
+ leftViewController?.beginAppearanceTransition(true, animated: true)
|
|
|
+ }
|
|
|
+ openLeftWithVelocity(panInfo.velocity)
|
|
|
+
|
|
|
+ track(.LeftFlickOpen)
|
|
|
+ } else {
|
|
|
+ if LeftPanState.wasHiddenAtStartOfPan {
|
|
|
+ leftViewController?.beginAppearanceTransition(false, animated: true)
|
|
|
+ }
|
|
|
+ closeLeftWithVelocity(panInfo.velocity)
|
|
|
+ setCloseWindowLevel()
|
|
|
+
|
|
|
+ track(.LeftFlickClose)
|
|
|
+
|
|
|
+ }
|
|
|
+ case UIGestureRecognizerState.Failed, UIGestureRecognizerState.Possible:
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ LeftPanState.lastState = panGesture.state
|
|
|
+ }
|
|
|
+
|
|
|
+ struct RightPanState {
|
|
|
+ static var frameAtStartOfPan: CGRect = CGRectZero
|
|
|
+ static var startPointOfPan: CGPoint = CGPointZero
|
|
|
+ static var wasOpenAtStartOfPan: Bool = false
|
|
|
+ static var wasHiddenAtStartOfPan: Bool = false
|
|
|
+ static var lastState : UIGestureRecognizerState = .Ended
|
|
|
+ }
|
|
|
+
|
|
|
+ func handleRightPanGesture(panGesture: UIPanGestureRecognizer) {
|
|
|
+
|
|
|
+ if !isTagetViewController() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if isLeftOpen() {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ switch panGesture.state {
|
|
|
+ case UIGestureRecognizerState.Began:
|
|
|
+ if RightPanState.lastState != .Ended && RightPanState.lastState != .Cancelled && RightPanState.lastState != .Failed {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if isRightHidden() {
|
|
|
+ self.delegate?.rightWillOpen?()
|
|
|
+ } else {
|
|
|
+ self.delegate?.rightWillClose?()
|
|
|
+ }
|
|
|
+
|
|
|
+ RightPanState.frameAtStartOfPan = rightContainerView.frame
|
|
|
+ RightPanState.startPointOfPan = panGesture.locationInView(view)
|
|
|
+ RightPanState.wasOpenAtStartOfPan = isRightOpen()
|
|
|
+ RightPanState.wasHiddenAtStartOfPan = isRightHidden()
|
|
|
+
|
|
|
+ rightViewController?.beginAppearanceTransition(RightPanState.wasHiddenAtStartOfPan, animated: true)
|
|
|
+
|
|
|
+ addShadowToView(rightContainerView)
|
|
|
+ setOpenWindowLevel()
|
|
|
+ case UIGestureRecognizerState.Changed:
|
|
|
+ if RightPanState.lastState != .Began && RightPanState.lastState != .Changed {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let translation: CGPoint = panGesture.translationInView(panGesture.view!)
|
|
|
+ rightContainerView.frame = applyRightTranslation(translation, toFrame: RightPanState.frameAtStartOfPan)
|
|
|
+ applyRightOpacity()
|
|
|
+ applyRightContentViewScale()
|
|
|
+
|
|
|
+ case UIGestureRecognizerState.Ended, UIGestureRecognizerState.Cancelled:
|
|
|
+ if RightPanState.lastState != .Changed {
|
|
|
+ setCloseWindowLevel()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let velocity: CGPoint = panGesture.velocityInView(panGesture.view)
|
|
|
+ let panInfo: PanInfo = panRightResultInfoForVelocity(velocity)
|
|
|
+
|
|
|
+ if panInfo.action == .Open {
|
|
|
+ if !RightPanState.wasHiddenAtStartOfPan {
|
|
|
+ rightViewController?.beginAppearanceTransition(true, animated: true)
|
|
|
+ }
|
|
|
+ openRightWithVelocity(panInfo.velocity)
|
|
|
+
|
|
|
+ track(.RightFlickOpen)
|
|
|
+ } else {
|
|
|
+ if RightPanState.wasHiddenAtStartOfPan {
|
|
|
+ rightViewController?.beginAppearanceTransition(false, animated: true)
|
|
|
+ }
|
|
|
+ closeRightWithVelocity(panInfo.velocity)
|
|
|
+ setCloseWindowLevel()
|
|
|
+
|
|
|
+ track(.RightFlickClose)
|
|
|
+ }
|
|
|
+ case UIGestureRecognizerState.Failed, UIGestureRecognizerState.Possible:
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ RightPanState.lastState = panGesture.state
|
|
|
+ }
|
|
|
+
|
|
|
+ public func openLeftWithVelocity(velocity: CGFloat) {
|
|
|
+ let xOrigin: CGFloat = leftContainerView.frame.origin.x
|
|
|
+ let finalXOrigin: CGFloat = 0.0
|
|
|
+
|
|
|
+ var frame = leftContainerView.frame;
|
|
|
+ frame.origin.x = finalXOrigin;
|
|
|
+
|
|
|
+ var duration: NSTimeInterval = Double(SlideMenuOptions.animationDuration)
|
|
|
+ if velocity != 0.0 {
|
|
|
+ duration = Double(fabs(xOrigin - finalXOrigin) / velocity)
|
|
|
+ duration = Double(fmax(0.1, fmin(1.0, duration)))
|
|
|
+ }
|
|
|
+
|
|
|
+ addShadowToView(leftContainerView)
|
|
|
+
|
|
|
+ UIView.animateWithDuration(duration, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { [weak self]() -> Void in
|
|
|
+ if let strongSelf = self {
|
|
|
+ strongSelf.leftContainerView.frame = frame
|
|
|
+ strongSelf.opacityView.layer.opacity = Float(SlideMenuOptions.contentViewOpacity)
|
|
|
+
|
|
|
+ SlideMenuOptions.contentViewDrag == true ? (strongSelf.mainContainerView.transform = CGAffineTransformMakeTranslation(SlideMenuOptions.leftViewWidth, 0)) : (strongSelf.mainContainerView.transform = CGAffineTransformMakeScale(SlideMenuOptions.contentViewScale, SlideMenuOptions.contentViewScale))
|
|
|
+
|
|
|
+ }
|
|
|
+ }) { [weak self](Bool) -> Void in
|
|
|
+ if let strongSelf = self {
|
|
|
+ strongSelf.disableContentInteraction()
|
|
|
+ strongSelf.leftViewController?.endAppearanceTransition()
|
|
|
+ strongSelf.delegate?.leftDidOpen?()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func openRightWithVelocity(velocity: CGFloat) {
|
|
|
+ let xOrigin: CGFloat = rightContainerView.frame.origin.x
|
|
|
+
|
|
|
+ // CGFloat finalXOrigin = SlideMenuOptions.rightViewOverlapWidth;
|
|
|
+ let finalXOrigin: CGFloat = CGRectGetWidth(view.bounds) - rightContainerView.frame.size.width
|
|
|
+
|
|
|
+ var frame = rightContainerView.frame
|
|
|
+ frame.origin.x = finalXOrigin
|
|
|
+
|
|
|
+ var duration: NSTimeInterval = Double(SlideMenuOptions.animationDuration)
|
|
|
+ if velocity != 0.0 {
|
|
|
+ duration = Double(fabs(xOrigin - CGRectGetWidth(view.bounds)) / velocity)
|
|
|
+ duration = Double(fmax(0.1, fmin(1.0, duration)))
|
|
|
+ }
|
|
|
+
|
|
|
+ addShadowToView(rightContainerView)
|
|
|
+
|
|
|
+ UIView.animateWithDuration(duration, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { [weak self]() -> Void in
|
|
|
+ if let strongSelf = self {
|
|
|
+ strongSelf.rightContainerView.frame = frame
|
|
|
+ strongSelf.opacityView.layer.opacity = Float(SlideMenuOptions.contentViewOpacity)
|
|
|
+
|
|
|
+ SlideMenuOptions.contentViewDrag == true ? (strongSelf.mainContainerView.transform = CGAffineTransformMakeTranslation(-SlideMenuOptions.rightViewWidth, 0)) : (strongSelf.mainContainerView.transform = CGAffineTransformMakeScale(SlideMenuOptions.contentViewScale, SlideMenuOptions.contentViewScale))
|
|
|
+ }
|
|
|
+ }) { [weak self](Bool) -> Void in
|
|
|
+ if let strongSelf = self {
|
|
|
+ strongSelf.disableContentInteraction()
|
|
|
+ strongSelf.rightViewController?.endAppearanceTransition()
|
|
|
+ strongSelf.delegate?.rightDidOpen?()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func closeLeftWithVelocity(velocity: CGFloat) {
|
|
|
+
|
|
|
+ let xOrigin: CGFloat = leftContainerView.frame.origin.x
|
|
|
+ let finalXOrigin: CGFloat = leftMinOrigin()
|
|
|
+
|
|
|
+ var frame: CGRect = leftContainerView.frame;
|
|
|
+ frame.origin.x = finalXOrigin
|
|
|
+
|
|
|
+ var duration: NSTimeInterval = Double(SlideMenuOptions.animationDuration)
|
|
|
+ if velocity != 0.0 {
|
|
|
+ duration = Double(fabs(xOrigin - finalXOrigin) / velocity)
|
|
|
+ duration = Double(fmax(0.1, fmin(1.0, duration)))
|
|
|
+ }
|
|
|
+
|
|
|
+ UIView.animateWithDuration(duration, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { [weak self]() -> Void in
|
|
|
+ if let strongSelf = self {
|
|
|
+ strongSelf.leftContainerView.frame = frame
|
|
|
+ strongSelf.opacityView.layer.opacity = 0.0
|
|
|
+ strongSelf.mainContainerView.transform = CGAffineTransformMakeScale(1.0, 1.0)
|
|
|
+ }
|
|
|
+ }) { [weak self](Bool) -> Void in
|
|
|
+ if let strongSelf = self {
|
|
|
+ strongSelf.removeShadow(strongSelf.leftContainerView)
|
|
|
+ strongSelf.enableContentInteraction()
|
|
|
+ strongSelf.leftViewController?.endAppearanceTransition()
|
|
|
+ strongSelf.delegate?.leftDidClose?()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public func closeRightWithVelocity(velocity: CGFloat) {
|
|
|
+
|
|
|
+ let xOrigin: CGFloat = rightContainerView.frame.origin.x
|
|
|
+ let finalXOrigin: CGFloat = CGRectGetWidth(view.bounds)
|
|
|
+
|
|
|
+ var frame: CGRect = rightContainerView.frame
|
|
|
+ frame.origin.x = finalXOrigin
|
|
|
+
|
|
|
+ var duration: NSTimeInterval = Double(SlideMenuOptions.animationDuration)
|
|
|
+ if velocity != 0.0 {
|
|
|
+ duration = Double(fabs(xOrigin - CGRectGetWidth(view.bounds)) / velocity)
|
|
|
+ duration = Double(fmax(0.1, fmin(1.0, duration)))
|
|
|
+ }
|
|
|
+
|
|
|
+ UIView.animateWithDuration(duration, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { [weak self]() -> Void in
|
|
|
+ if let strongSelf = self {
|
|
|
+ strongSelf.rightContainerView.frame = frame
|
|
|
+ strongSelf.opacityView.layer.opacity = 0.0
|
|
|
+ strongSelf.mainContainerView.transform = CGAffineTransformMakeScale(1.0, 1.0)
|
|
|
+ }
|
|
|
+ }) { [weak self](Bool) -> Void in
|
|
|
+ if let strongSelf = self {
|
|
|
+ strongSelf.removeShadow(strongSelf.rightContainerView)
|
|
|
+ strongSelf.enableContentInteraction()
|
|
|
+ strongSelf.rightViewController?.endAppearanceTransition()
|
|
|
+ strongSelf.delegate?.rightDidClose?()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public override func toggleLeft() {
|
|
|
+ if isLeftOpen() {
|
|
|
+ closeLeft()
|
|
|
+ setCloseWindowLevel()
|
|
|
+ // Tracking of close tap is put in here. Because closeMenu is due to be call even when the menu tap.
|
|
|
+
|
|
|
+ track(.LeftTapClose)
|
|
|
+ } else {
|
|
|
+ openLeft()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func isLeftOpen() -> Bool {
|
|
|
+ return leftViewController != nil && leftContainerView.frame.origin.x == 0.0
|
|
|
+ }
|
|
|
+
|
|
|
+ public func isLeftHidden() -> Bool {
|
|
|
+ return leftContainerView.frame.origin.x <= leftMinOrigin()
|
|
|
+ }
|
|
|
+
|
|
|
+ public override func toggleRight() {
|
|
|
+ if isRightOpen() {
|
|
|
+ closeRight()
|
|
|
+ setCloseWindowLevel()
|
|
|
+
|
|
|
+ // Tracking of close tap is put in here. Because closeMenu is due to be call even when the menu tap.
|
|
|
+ track(.RightTapClose)
|
|
|
+ } else {
|
|
|
+ openRight()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func isRightOpen() -> Bool {
|
|
|
+ return rightViewController != nil && rightContainerView.frame.origin.x == CGRectGetWidth(view.bounds) - rightContainerView.frame.size.width
|
|
|
+ }
|
|
|
+
|
|
|
+ public func isRightHidden() -> Bool {
|
|
|
+ return rightContainerView.frame.origin.x >= CGRectGetWidth(view.bounds)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func changeMainViewController(mainViewController: UIViewController, close: Bool) {
|
|
|
+
|
|
|
+ removeViewController(self.mainViewController)
|
|
|
+ self.mainViewController = mainViewController
|
|
|
+ setUpViewController(mainContainerView, targetViewController: mainViewController)
|
|
|
+ if (close) {
|
|
|
+ closeLeft()
|
|
|
+ closeRight()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func changeLeftViewWidth(width: CGFloat) {
|
|
|
+
|
|
|
+ SlideMenuOptions.leftViewWidth = width;
|
|
|
+ var leftFrame: CGRect = view.bounds
|
|
|
+ leftFrame.size.width = width
|
|
|
+ leftFrame.origin.x = leftMinOrigin();
|
|
|
+ let leftOffset: CGFloat = 0
|
|
|
+ leftFrame.origin.y = leftFrame.origin.y + leftOffset
|
|
|
+ leftFrame.size.height = leftFrame.size.height - leftOffset
|
|
|
+ leftContainerView.frame = leftFrame;
|
|
|
+ }
|
|
|
+
|
|
|
+ public func changeRightViewWidth(width: CGFloat) {
|
|
|
+
|
|
|
+ SlideMenuOptions.rightBezelWidth = width;
|
|
|
+ var rightFrame: CGRect = view.bounds
|
|
|
+ rightFrame.size.width = width
|
|
|
+ rightFrame.origin.x = rightMinOrigin()
|
|
|
+ let rightOffset: CGFloat = 0
|
|
|
+ rightFrame.origin.y = rightFrame.origin.y + rightOffset;
|
|
|
+ rightFrame.size.height = rightFrame.size.height - rightOffset
|
|
|
+ rightContainerView.frame = rightFrame;
|
|
|
+ }
|
|
|
+
|
|
|
+ public func changeLeftViewController(leftViewController: UIViewController, closeLeft:Bool) {
|
|
|
+
|
|
|
+ removeViewController(self.leftViewController)
|
|
|
+ self.leftViewController = leftViewController
|
|
|
+ setUpViewController(leftContainerView, targetViewController: leftViewController)
|
|
|
+ if closeLeft {
|
|
|
+ self.closeLeft()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func changeRightViewController(rightViewController: UIViewController, closeRight:Bool) {
|
|
|
+ removeViewController(self.rightViewController)
|
|
|
+ self.rightViewController = rightViewController;
|
|
|
+ setUpViewController(rightContainerView, targetViewController: rightViewController)
|
|
|
+ if closeRight {
|
|
|
+ self.closeRight()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private func leftMinOrigin() -> CGFloat {
|
|
|
+ return -SlideMenuOptions.leftViewWidth
|
|
|
+ }
|
|
|
+
|
|
|
+ private func rightMinOrigin() -> CGFloat {
|
|
|
+ return CGRectGetWidth(view.bounds)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private func panLeftResultInfoForVelocity(velocity: CGPoint) -> PanInfo {
|
|
|
+
|
|
|
+ let thresholdVelocity: CGFloat = 1000.0
|
|
|
+ let pointOfNoReturn: CGFloat = CGFloat(floor(leftMinOrigin())) + SlideMenuOptions.pointOfNoReturnWidth
|
|
|
+ let leftOrigin: CGFloat = leftContainerView.frame.origin.x
|
|
|
+
|
|
|
+ var panInfo: PanInfo = PanInfo(action: .Close, shouldBounce: false, velocity: 0.0)
|
|
|
+
|
|
|
+ panInfo.action = leftOrigin <= pointOfNoReturn ? .Close : .Open;
|
|
|
+
|
|
|
+ if velocity.x >= thresholdVelocity {
|
|
|
+ panInfo.action = .Open
|
|
|
+ panInfo.velocity = velocity.x
|
|
|
+ } else if velocity.x <= (-1.0 * thresholdVelocity) {
|
|
|
+ panInfo.action = .Close
|
|
|
+ panInfo.velocity = velocity.x
|
|
|
+ }
|
|
|
+
|
|
|
+ return panInfo
|
|
|
+ }
|
|
|
+
|
|
|
+ private func panRightResultInfoForVelocity(velocity: CGPoint) -> PanInfo {
|
|
|
+
|
|
|
+ let thresholdVelocity: CGFloat = -1000.0
|
|
|
+ let pointOfNoReturn: CGFloat = CGFloat(floor(CGRectGetWidth(view.bounds)) - SlideMenuOptions.pointOfNoReturnWidth)
|
|
|
+ let rightOrigin: CGFloat = rightContainerView.frame.origin.x
|
|
|
+
|
|
|
+ var panInfo: PanInfo = PanInfo(action: .Close, shouldBounce: false, velocity: 0.0)
|
|
|
+
|
|
|
+ panInfo.action = rightOrigin >= pointOfNoReturn ? .Close : .Open
|
|
|
+
|
|
|
+ if velocity.x <= thresholdVelocity {
|
|
|
+ panInfo.action = .Open
|
|
|
+ panInfo.velocity = velocity.x
|
|
|
+ } else if (velocity.x >= (-1.0 * thresholdVelocity)) {
|
|
|
+ panInfo.action = .Close
|
|
|
+ panInfo.velocity = velocity.x
|
|
|
+ }
|
|
|
+
|
|
|
+ return panInfo
|
|
|
+ }
|
|
|
+
|
|
|
+ private func applyLeftTranslation(translation: CGPoint, toFrame:CGRect) -> CGRect {
|
|
|
+
|
|
|
+ var newOrigin: CGFloat = toFrame.origin.x
|
|
|
+ newOrigin += translation.x
|
|
|
+
|
|
|
+ let minOrigin: CGFloat = leftMinOrigin()
|
|
|
+ let maxOrigin: CGFloat = 0.0
|
|
|
+ var newFrame: CGRect = toFrame
|
|
|
+
|
|
|
+ if newOrigin < minOrigin {
|
|
|
+ newOrigin = minOrigin
|
|
|
+ } else if newOrigin > maxOrigin {
|
|
|
+ newOrigin = maxOrigin
|
|
|
+ }
|
|
|
+
|
|
|
+ newFrame.origin.x = newOrigin
|
|
|
+ return newFrame
|
|
|
+ }
|
|
|
+
|
|
|
+ private func applyRightTranslation(translation: CGPoint, toFrame: CGRect) -> CGRect {
|
|
|
+
|
|
|
+ var newOrigin: CGFloat = toFrame.origin.x
|
|
|
+ newOrigin += translation.x
|
|
|
+
|
|
|
+ let minOrigin: CGFloat = rightMinOrigin()
|
|
|
+ let maxOrigin: CGFloat = rightMinOrigin() - rightContainerView.frame.size.width
|
|
|
+ var newFrame: CGRect = toFrame
|
|
|
+
|
|
|
+ if newOrigin > minOrigin {
|
|
|
+ newOrigin = minOrigin
|
|
|
+ } else if newOrigin < maxOrigin {
|
|
|
+ newOrigin = maxOrigin
|
|
|
+ }
|
|
|
+
|
|
|
+ newFrame.origin.x = newOrigin
|
|
|
+ return newFrame
|
|
|
+ }
|
|
|
+
|
|
|
+ private func getOpenedLeftRatio() -> CGFloat {
|
|
|
+
|
|
|
+ let width: CGFloat = leftContainerView.frame.size.width
|
|
|
+ let currentPosition: CGFloat = leftContainerView.frame.origin.x - leftMinOrigin()
|
|
|
+ return currentPosition / width
|
|
|
+ }
|
|
|
+
|
|
|
+ private func getOpenedRightRatio() -> CGFloat {
|
|
|
+
|
|
|
+ let width: CGFloat = rightContainerView.frame.size.width
|
|
|
+ let currentPosition: CGFloat = rightContainerView.frame.origin.x
|
|
|
+ return -(currentPosition - CGRectGetWidth(view.bounds)) / width
|
|
|
+ }
|
|
|
+
|
|
|
+ private func applyLeftOpacity() {
|
|
|
+
|
|
|
+ let openedLeftRatio: CGFloat = getOpenedLeftRatio()
|
|
|
+ let opacity: CGFloat = SlideMenuOptions.contentViewOpacity * openedLeftRatio
|
|
|
+ opacityView.layer.opacity = Float(opacity)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private func applyRightOpacity() {
|
|
|
+ let openedRightRatio: CGFloat = getOpenedRightRatio()
|
|
|
+ let opacity: CGFloat = SlideMenuOptions.contentViewOpacity * openedRightRatio
|
|
|
+ opacityView.layer.opacity = Float(opacity)
|
|
|
+ }
|
|
|
+
|
|
|
+ private func applyLeftContentViewScale() {
|
|
|
+ let openedLeftRatio: CGFloat = getOpenedLeftRatio()
|
|
|
+ let scale: CGFloat = 1.0 - ((1.0 - SlideMenuOptions.contentViewScale) * openedLeftRatio);
|
|
|
+ let drag: CGFloat = SlideMenuOptions.leftViewWidth + leftContainerView.frame.origin.x
|
|
|
+
|
|
|
+ SlideMenuOptions.contentViewDrag == true ? (mainContainerView.transform = CGAffineTransformMakeTranslation(drag, 0)) : (mainContainerView.transform = CGAffineTransformMakeScale(scale, scale))
|
|
|
+ }
|
|
|
+
|
|
|
+ private func applyRightContentViewScale() {
|
|
|
+ let openedRightRatio: CGFloat = getOpenedRightRatio()
|
|
|
+ let scale: CGFloat = 1.0 - ((1.0 - SlideMenuOptions.contentViewScale) * openedRightRatio)
|
|
|
+ let drag: CGFloat = rightContainerView.frame.origin.x - mainContainerView.frame.size.width
|
|
|
+
|
|
|
+ SlideMenuOptions.contentViewDrag == true ? (mainContainerView.transform = CGAffineTransformMakeTranslation(drag, 0)) : (mainContainerView.transform = CGAffineTransformMakeScale(scale, scale))
|
|
|
+ }
|
|
|
+
|
|
|
+ private func addShadowToView(targetContainerView: UIView) {
|
|
|
+ targetContainerView.layer.masksToBounds = false
|
|
|
+ targetContainerView.layer.shadowOffset = SlideMenuOptions.shadowOffset
|
|
|
+ targetContainerView.layer.shadowOpacity = Float(SlideMenuOptions.shadowOpacity)
|
|
|
+ targetContainerView.layer.shadowRadius = SlideMenuOptions.shadowRadius
|
|
|
+ targetContainerView.layer.shadowPath = UIBezierPath(rect: targetContainerView.bounds).CGPath
|
|
|
+ }
|
|
|
+
|
|
|
+ private func removeShadow(targetContainerView: UIView) {
|
|
|
+ targetContainerView.layer.masksToBounds = true
|
|
|
+ mainContainerView.layer.opacity = 1.0
|
|
|
+ }
|
|
|
+
|
|
|
+ private func removeContentOpacity() {
|
|
|
+ opacityView.layer.opacity = 0.0
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private func addContentOpacity() {
|
|
|
+ opacityView.layer.opacity = Float(SlideMenuOptions.contentViewOpacity)
|
|
|
+ }
|
|
|
+
|
|
|
+ private func disableContentInteraction() {
|
|
|
+ mainContainerView.userInteractionEnabled = false
|
|
|
+ }
|
|
|
+
|
|
|
+ private func enableContentInteraction() {
|
|
|
+ mainContainerView.userInteractionEnabled = true
|
|
|
+ }
|
|
|
+
|
|
|
+ private func setOpenWindowLevel() {
|
|
|
+ if (SlideMenuOptions.hideStatusBar) {
|
|
|
+ dispatch_async(dispatch_get_main_queue(), {
|
|
|
+ if let window = UIApplication.sharedApplication().keyWindow {
|
|
|
+ window.windowLevel = UIWindowLevelStatusBar + 1
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private func setCloseWindowLevel() {
|
|
|
+ if (SlideMenuOptions.hideStatusBar) {
|
|
|
+ dispatch_async(dispatch_get_main_queue(), {
|
|
|
+ if let window = UIApplication.sharedApplication().keyWindow {
|
|
|
+ window.windowLevel = UIWindowLevelNormal
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private func setUpViewController(targetView: UIView, targetViewController: UIViewController?) {
|
|
|
+ if let viewController = targetViewController {
|
|
|
+ addChildViewController(viewController)
|
|
|
+ viewController.view.frame = targetView.bounds
|
|
|
+ targetView.addSubview(viewController.view)
|
|
|
+ viewController.didMoveToParentViewController(self)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private func removeViewController(viewController: UIViewController?) {
|
|
|
+ if let _viewController = viewController {
|
|
|
+ _viewController.view.layer.removeAllAnimations()
|
|
|
+ _viewController.willMoveToParentViewController(nil)
|
|
|
+ _viewController.view.removeFromSuperview()
|
|
|
+ _viewController.removeFromParentViewController()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public func closeLeftNonAnimation(){
|
|
|
+ setCloseWindowLevel()
|
|
|
+ let finalXOrigin: CGFloat = leftMinOrigin()
|
|
|
+ var frame: CGRect = leftContainerView.frame;
|
|
|
+ frame.origin.x = finalXOrigin
|
|
|
+ leftContainerView.frame = frame
|
|
|
+ opacityView.layer.opacity = 0.0
|
|
|
+ mainContainerView.transform = CGAffineTransformMakeScale(1.0, 1.0)
|
|
|
+ removeShadow(leftContainerView)
|
|
|
+ enableContentInteraction()
|
|
|
+ }
|
|
|
+
|
|
|
+ public func closeRightNonAnimation(){
|
|
|
+ setCloseWindowLevel()
|
|
|
+ let finalXOrigin: CGFloat = CGRectGetWidth(view.bounds)
|
|
|
+ var frame: CGRect = rightContainerView.frame
|
|
|
+ frame.origin.x = finalXOrigin
|
|
|
+ rightContainerView.frame = frame
|
|
|
+ opacityView.layer.opacity = 0.0
|
|
|
+ mainContainerView.transform = CGAffineTransformMakeScale(1.0, 1.0)
|
|
|
+ removeShadow(rightContainerView)
|
|
|
+ enableContentInteraction()
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: UIGestureRecognizerDelegate
|
|
|
+ public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
|
|
|
+
|
|
|
+ let point: CGPoint = touch.locationInView(view)
|
|
|
+
|
|
|
+ if gestureRecognizer == leftPanGesture {
|
|
|
+ return slideLeftForGestureRecognizer(gestureRecognizer, point: point)
|
|
|
+ } else if gestureRecognizer == rightPanGesture {
|
|
|
+ return slideRightViewForGestureRecognizer(gestureRecognizer, withTouchPoint: point)
|
|
|
+ } else if gestureRecognizer == leftTapGesture {
|
|
|
+ return isLeftOpen() && !isPointContainedWithinLeftRect(point)
|
|
|
+ } else if gestureRecognizer == rightTapGesture {
|
|
|
+ return isRightOpen() && !isPointContainedWithinRightRect(point)
|
|
|
+ }
|
|
|
+
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ // returning true here helps if the main view is fullwidth with a scrollview
|
|
|
+ public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
|
|
+ return SlideMenuOptions.simultaneousGestureRecognizers
|
|
|
+ }
|
|
|
+
|
|
|
+ private func slideLeftForGestureRecognizer( gesture: UIGestureRecognizer, point:CGPoint) -> Bool{
|
|
|
+ return isLeftOpen() || SlideMenuOptions.panFromBezel && isLeftPointContainedWithinBezelRect(point)
|
|
|
+ }
|
|
|
+
|
|
|
+ private func isLeftPointContainedWithinBezelRect(point: CGPoint) -> Bool{
|
|
|
+ if let bezelWidth = SlideMenuOptions.leftBezelWidth {
|
|
|
+ var leftBezelRect: CGRect = CGRectZero
|
|
|
+ var tempRect: CGRect = CGRectZero
|
|
|
+
|
|
|
+ CGRectDivide(view.bounds, &leftBezelRect, &tempRect, bezelWidth, CGRectEdge.MinXEdge)
|
|
|
+ return CGRectContainsPoint(leftBezelRect, point)
|
|
|
+ } else {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private func isPointContainedWithinLeftRect(point: CGPoint) -> Bool {
|
|
|
+ return CGRectContainsPoint(leftContainerView.frame, point)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private func slideRightViewForGestureRecognizer(gesture: UIGestureRecognizer, withTouchPoint point: CGPoint) -> Bool {
|
|
|
+ return isRightOpen() || SlideMenuOptions.rightPanFromBezel && isRightPointContainedWithinBezelRect(point)
|
|
|
+ }
|
|
|
+
|
|
|
+ private func isRightPointContainedWithinBezelRect(point: CGPoint) -> Bool {
|
|
|
+ if let rightBezelWidth = SlideMenuOptions.rightBezelWidth {
|
|
|
+ var rightBezelRect: CGRect = CGRectZero
|
|
|
+ var tempRect: CGRect = CGRectZero
|
|
|
+ let bezelWidth: CGFloat = CGRectGetWidth(view.bounds) - rightBezelWidth
|
|
|
+
|
|
|
+ CGRectDivide(view.bounds, &tempRect, &rightBezelRect, bezelWidth, CGRectEdge.MinXEdge)
|
|
|
+
|
|
|
+ return CGRectContainsPoint(rightBezelRect, point)
|
|
|
+ } else {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private func isPointContainedWithinRightRect(point: CGPoint) -> Bool {
|
|
|
+ return CGRectContainsPoint(rightContainerView.frame, point)
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+extension UIViewController {
|
|
|
+
|
|
|
+ public func slideMenuController() -> SlideMenuController? {
|
|
|
+ var viewController: UIViewController? = self
|
|
|
+ while viewController != nil {
|
|
|
+ if viewController is SlideMenuController {
|
|
|
+ return viewController as? SlideMenuController
|
|
|
+ }
|
|
|
+ viewController = viewController?.parentViewController
|
|
|
+ }
|
|
|
+ return nil;
|
|
|
+ }
|
|
|
+
|
|
|
+ public func addLeftBarButtonWithImage(buttonImage: UIImage) {
|
|
|
+ let leftButton: UIBarButtonItem = UIBarButtonItem(image: buttonImage, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(self.toggleLeft))
|
|
|
+ navigationItem.leftBarButtonItem = leftButton;
|
|
|
+ }
|
|
|
+
|
|
|
+ public func addRightBarButtonWithImage(buttonImage: UIImage) {
|
|
|
+ let rightButton: UIBarButtonItem = UIBarButtonItem(image: buttonImage, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(self.toggleRight))
|
|
|
+ navigationItem.rightBarButtonItem = rightButton;
|
|
|
+ }
|
|
|
+
|
|
|
+ public func toggleLeft() {
|
|
|
+ slideMenuController()?.toggleLeft()
|
|
|
+ }
|
|
|
+
|
|
|
+ public func toggleRight() {
|
|
|
+ slideMenuController()?.toggleRight()
|
|
|
+ }
|
|
|
+
|
|
|
+ public func openLeft() {
|
|
|
+ slideMenuController()?.openLeft()
|
|
|
+ }
|
|
|
+
|
|
|
+ public func openRight() {
|
|
|
+ slideMenuController()?.openRight() }
|
|
|
+
|
|
|
+ public func closeLeft() {
|
|
|
+ slideMenuController()?.closeLeft()
|
|
|
+ }
|
|
|
+
|
|
|
+ public func closeRight() {
|
|
|
+ slideMenuController()?.closeRight()
|
|
|
+ }
|
|
|
+
|
|
|
+ // Please specify if you want menu gesuture give priority to than targetScrollView
|
|
|
+ public func addPriorityToMenuGesuture(targetScrollView: UIScrollView) {
|
|
|
+ guard let slideController = slideMenuController(), let recognizers = slideController.view.gestureRecognizers else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for recognizer in recognizers where recognizer is UIPanGestureRecognizer {
|
|
|
+ targetScrollView.panGestureRecognizer.requireGestureRecognizerToFail(recognizer)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|