| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051 |
- //
- // 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)
- }
- }
- }
|