Code Monkey home page Code Monkey logo

Comments (16)

PankovSerge avatar PankovSerge commented on July 3, 2024 3

@pappzsolt100 your solution is not perfect and so complex.

Quick workaround, but it's not clear too:

        outterView = UIView(frame: CGRectMake(sideMenuContainerView.frame.width, 0,
            sourceView.frame.width - sideMenuContainerView.frame.width,
            sourceView.frame.height))
        outterView.backgroundColor = UIColor.clearColor()
        let tapRecognizer = UITapGestureRecognizer(target: self, action: "hideSideMenu")
        outterView.addGestureRecognizer(tapRecognizer)
        outterView.userInteractionEnabled = false
        sourceView.addSubview(outterView)

and change user interaction of outerView in

private func toggleMenu (shouldOpen: Bool) {
        outterView.userInteractionEnabled = shouldOpen

it's all !
Have a nice day!

from enswiftsidemenu.

pappzsolt100 avatar pappzsolt100 commented on July 3, 2024 2

My solution for this. I've added the following code in ENSideMenu.swift main init:
let outterView = UIView(frame: CGRectMake(0, 0, sourceView.bounds.width, sourceView.bounds.height))
outterView.backgroundColor = UIColor.clearColor()
let tapRecognizer = UITapGestureRecognizer(target: self, action: "hideSideMenu")
outterView.addGestureRecognizer(tapRecognizer)
sideMenuContainerView.addSubview(outterView)

and adjust the menu width and animation like this:

public convenience init(sourceView: UIView, menuViewController: UIViewController, menuPosition: ENSideMenuPosition) {
...
let menuFrame = CGRectMake(0, 0, sideMenuContainerView.bounds.width-30, sideMenuContainerView.bounds.height)
self.menuViewController.view.frame = menuFrame
...
}

func updateFrame() {
...
isMenuOpen ? 0 : -sourceView.frame.size.width-0.0 :
...
}

private func toggleMenu (shouldOpen: Bool) {
...
destFrame = CGRectMake((shouldOpen) ? -2.0 : -sourceView.frame.size.width, 0, sourceView.frame.size.width, height)
...
}

I hope its help!

from enswiftsidemenu.

lakhshya avatar lakhshya commented on July 3, 2024 1

Define outterView in ENSideMenu
private var outterView: UIView = UIView()

Add @PankovSerge 's code in the public init of ENSideMenu

from enswiftsidemenu.

djdance avatar djdance commented on July 3, 2024 1

Swift 3.0 with animated dimming

        //beefore sideMenuContainerView!
        outterView = UIView(frame: CGRect(x:0, y:0,width:sourceView.frame.width,height:sourceView.frame.height))
        outterView.backgroundColor = UIColor.black
        //outterView.layer.opacity=0.2
        let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ENSideMenu.hideSideMenu))
        outterView.addGestureRecognizer(tapRecognizer)
        outterView.isUserInteractionEnabled = false
        outterView.isHidden = true
        outterView.alpha=0
        sourceView.addSubview(outterView)

and in toggleMenu

// Fade in/out
        if shouldOpen {
            outterView.isUserInteractionEnabled = shouldOpen
            outterView.isHidden = !shouldOpen
            UIView.animate(withDuration: 0.4, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {self.outterView.alpha = 0.5}, completion: nil)
        } else  {
            UIView.animate(withDuration: 0.4, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {self.outterView.alpha = 0.0}, completion: {Void in
                self.outterView.isUserInteractionEnabled = shouldOpen
                self.outterView.isHidden = !shouldOpen
            })
        }

from enswiftsidemenu.

kamal0289 avatar kamal0289 commented on July 3, 2024 1

Where I put this code in this class pls :

import UIKit

public protocol ENSideMenuDelegate: class {
func sideMenuWillOpen()
func sideMenuWillClose()
func sideMenuShouldOpenSideMenu () -> Bool
func sideMenuDidOpen()
func sideMenuDidClose()
}

public protocol ENSideMenuProtocol: class {
// var sideMenu : ENSideMenu? { get }
// func setContentViewController(_ contentViewController: UIViewController)
var sideMenu : ENSideMenu? { get }
func setContentViewController(contentViewController: UIViewController, push:Bool)
}

public enum ENSideMenuAnimation : Int {
case none
case default
}
/**
The position of the side view on the screen.

  • Left: Left side of the screen
  • Right: Right side of the screen
    */
    public enum ENSideMenuPosition : Int {
    case left
    case right
    }

public extension UIViewController {
/**
Changes current state of side menu view.
/
public func toggleSideMenuView () {
sideMenuController()?.sideMenu?.toggleMenu()
}
/
*
Hides the side menu view.
/
public func hideSideMenuView () {
sideMenuController()?.sideMenu?.hideSideMenu()
}
/
*
Shows the side menu view.
*/
public func showSideMenuView () {
sideMenuController()?.sideMenu?.showSideMenu()
}

/**
Returns a Boolean value indicating whether the side menu is showed.

:returns: BOOL value
*/
public func isSideMenuOpen () -> Bool {
    let sieMenuOpen = sideMenuController()?.sideMenu?.isMenuOpen
    return sieMenuOpen!
}

/**
 * You must call this method from viewDidLayoutSubviews in your content view controlers so it fixes size and position of the side menu when the screen
 * rotates.
 * A convenient way to do it might be creating a subclass of UIViewController that does precisely that and then subclassing your view controllers from it.
 */
func fixSideMenuSize() {
    if let navController = navigationController as? ENSideMenuNavigationController {
        navController.sideMenu?.updateFrame()
    }
}
/**
Returns a view controller containing a side menu

:returns: A `UIViewController`responding to `ENSideMenuProtocol` protocol
*/
public func sideMenuController () -> ENSideMenuProtocol? {
    var iteration : UIViewController? = parent
    if (iteration == nil) {
        return topMostController()
    }
    repeat {
        if (iteration is ENSideMenuProtocol) {
            return iteration as? ENSideMenuProtocol
        } else if (iteration?.parent != nil && iteration?.parent != iteration) {
            iteration = iteration!.parent
        } else {
            iteration = nil
        }
    } while (iteration != nil)

    return iteration as? ENSideMenuProtocol
}

internal func topMostController () -> ENSideMenuProtocol? {
    var topController : UIViewController? = UIApplication.shared.keyWindow?.rootViewController
    if (topController is UITabBarController) {
        topController = (topController as! UITabBarController).selectedViewController
    }
    var lastMenuProtocol : ENSideMenuProtocol?
    while (topController?.presentedViewController != nil) {
        if(topController?.presentedViewController is ENSideMenuProtocol) {
            lastMenuProtocol = topController?.presentedViewController as? ENSideMenuProtocol
        }
        topController = topController?.presentedViewController
    }

    if (lastMenuProtocol != nil) {
        return lastMenuProtocol
    }
    else {
        return topController as? ENSideMenuProtocol
    }
}

}

open class ENSideMenu : NSObject, UIGestureRecognizerDelegate {
/// The width of the side menu view. The default value is 160.
open var menuWidth : CGFloat = 160.0 {
didSet {
needUpdateApperance = true
updateSideMenuApperanceIfNeeded()
updateFrame()
}
}
fileprivate var menuPosition:ENSideMenuPosition = .left
fileprivate var blurStyle: UIBlurEffectStyle = .light
/// A Boolean value indicating whether the bouncing effect is enabled. The default value is TRUE.
open var bouncingEnabled :Bool = true
/// The duration of the slide animation. Used only when bouncingEnabled is FALSE.
open var animationDuration = 0.4
fileprivate let sideMenuContainerView = UIView()
fileprivate(set) var sidemenuViewController : UIViewController!
fileprivate var animator : UIDynamicAnimator!
fileprivate var sourceView : UIView!
fileprivate var needUpdateApperance : Bool = false
/// The delegate of the side menu
open weak var delegate : ENSideMenuDelegate?
fileprivate(set) var isMenuOpen : Bool = false
/// A Boolean value indicating whether the left swipe is enabled.
open var allowLeftSwipe : Bool = true
/// A Boolean value indicating whether the right swipe is enabled.
open var allowRightSwipe : Bool = true
open var allowPanGesture : Bool = true
fileprivate var panRecognizer : UIPanGestureRecognizer?

/**
Initializes an instance of a `ENSideMenu` object.

:param: sourceView   The parent view of the side menu view.
:param: menuPosition The position of the side menu view.

:returns: An initialized `ENSideMenu` object, added to the specified view.
*/
public init(sourceView: UIView, menuPosition: ENSideMenuPosition, blurStyle: UIBlurEffectStyle = .light) {
    super.init()
    self.sourceView = sourceView
    self.menuPosition = menuPosition
    self.blurStyle = blurStyle
    self.setupMenuView()

    animator = UIDynamicAnimator(referenceView:sourceView)
    animator.delegate = self

    self.panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(ENSideMenu.handlePan(_:)))
    panRecognizer!.delegate = self
    sourceView.addGestureRecognizer(panRecognizer!)

    // Add right swipe gesture recognizer
    let rightSwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(ENSideMenu.handleGesture(_:)))
    rightSwipeGestureRecognizer.delegate = self
    rightSwipeGestureRecognizer.direction =  UISwipeGestureRecognizerDirection.right

    // Add left swipe gesture recognizer
    let leftSwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(ENSideMenu.handleGesture(_:)))
    leftSwipeGestureRecognizer.delegate = self
    leftSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirection.left

    if (menuPosition == .left) {
        sourceView.addGestureRecognizer(rightSwipeGestureRecognizer)
        sideMenuContainerView.addGestureRecognizer(leftSwipeGestureRecognizer)
    }
    else {
        sideMenuContainerView.addGestureRecognizer(rightSwipeGestureRecognizer)
        sourceView.addGestureRecognizer(leftSwipeGestureRecognizer)
    }

}
/**
Initializes an instance of a `ENSideMenu` object.

:param: sourceView         The parent view of the side menu view.
:param: sidemenuViewController A menu view controller object which will be placed in the side menu view.
:param: menuPosition       The position of the side menu view.

:returns: An initialized `ENSideMenu` object, added to the specified view, containing the specified menu view controller.
*/
public convenience init(sourceView: UIView, sidemenuViewController: UIViewController, menuPosition: ENSideMenuPosition, blurStyle: UIBlurEffectStyle = .light) {
    self.init(sourceView: sourceView, menuPosition: menuPosition, blurStyle: blurStyle)
    self.sidemenuViewController = sidemenuViewController
    sidemenuViewController.view.frame = sideMenuContainerView.bounds
    sidemenuViewController.view.autoresizingMask =  [.flexibleHeight, .flexibleWidth]
    sideMenuContainerView.addSubview(sidemenuViewController.view)
}
/**
Updates the frame of the side menu view.
*/
func updateFrame() {
    var width:CGFloat
    var height:CGFloat
    (width, height) = adjustFrameDimensions( sourceView.frame.size.width, height: sourceView.frame.size.height)
    let menuFrame = CGRect(
        x: (menuPosition == .left) ?
            isMenuOpen ? 0 : -menuWidth-1.0 :
            isMenuOpen ? width - menuWidth : width+1.0,
        y: sourceView.frame.origin.y,
        width: menuWidth,
        height: height
    )
    sideMenuContainerView.frame = menuFrame
}

fileprivate func adjustFrameDimensions( _ width: CGFloat, height: CGFloat ) -> (CGFloat,CGFloat) {
    if floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1 &&
        (UIApplication.shared.statusBarOrientation == UIInterfaceOrientation.landscapeRight ||
            UIApplication.shared.statusBarOrientation == UIInterfaceOrientation.landscapeLeft) {
                // iOS 7.1 or lower and landscape mode -> interchange width and height
                return (height, width)
    }
    else {
        return (width, height)
    }

}

fileprivate func setupMenuView() {

    
    // Configure side menu container
    updateFrame()

    sideMenuContainerView.backgroundColor = UIColor.clear
    sideMenuContainerView.clipsToBounds = false
    sideMenuContainerView.layer.masksToBounds = false
    sideMenuContainerView.layer.shadowOffset = (menuPosition == .left) ? CGSize(width: 1.0, height: 1.0) : CGSize(width: -1.0, height: -1.0)
    sideMenuContainerView.layer.shadowRadius = 1.0
    sideMenuContainerView.layer.shadowOpacity = 0.125
    sideMenuContainerView.layer.shadowPath = UIBezierPath(rect: sideMenuContainerView.bounds).cgPath

    sourceView.addSubview(sideMenuContainerView)

    if (NSClassFromString("UIVisualEffectView") != nil) {
        // Add blur view
        let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: blurStyle)) as UIVisualEffectView
        visualEffectView.frame = sideMenuContainerView.bounds
        visualEffectView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        sideMenuContainerView.addSubview(visualEffectView)
    }
    else {
        // TODO: add blur for ios 7
    }
}

fileprivate func toggleMenu (_ shouldOpen: Bool) {
    if shouldOpen, delegate?.sideMenuShouldOpenSideMenu() == false {
        return
    }
    updateSideMenuApperanceIfNeeded()
    isMenuOpen = shouldOpen
    var width:CGFloat
    var height:CGFloat
    (width, height) = adjustFrameDimensions( sourceView.frame.size.width, height: sourceView.frame.size.height)
    if (bouncingEnabled) {

        animator.removeAllBehaviors()

        var gravityDirectionX: CGFloat
        var pushMagnitude: CGFloat
        var boundaryPointX: CGFloat
        var boundaryPointY: CGFloat

        if (menuPosition == .left) {
            // Left side menu
            gravityDirectionX = (shouldOpen) ? 1 : -1
            pushMagnitude = (shouldOpen) ? 35 : -35
            boundaryPointX = (shouldOpen) ? menuWidth : -menuWidth-2
            boundaryPointY = 25
        }
        else {
            // Right side menu
            gravityDirectionX = (shouldOpen) ? -1 : 1
            pushMagnitude = (shouldOpen) ? -35 : 35
            boundaryPointX = (shouldOpen) ? width-menuWidth : width+menuWidth+2
            boundaryPointY =  -25
        }

        let gravityBehavior = UIGravityBehavior(items: [sideMenuContainerView])
        gravityBehavior.gravityDirection = CGVector(dx: gravityDirectionX,  dy: 0)
        animator.addBehavior(gravityBehavior)

        let collisionBehavior = UICollisionBehavior(items: [sideMenuContainerView])
        collisionBehavior.addBoundary(withIdentifier: "menuBoundary" as NSCopying, from: CGPoint(x: boundaryPointX, y: boundaryPointY),
            to: CGPoint(x: boundaryPointX, y: height))
        animator.addBehavior(collisionBehavior)

        let pushBehavior = UIPushBehavior(items: [sideMenuContainerView], mode: UIPushBehaviorMode.instantaneous)
        pushBehavior.magnitude = pushMagnitude
        animator.addBehavior(pushBehavior)

        let menuViewBehavior = UIDynamicItemBehavior(items: [sideMenuContainerView])
        menuViewBehavior.elasticity = 0.25
        animator.addBehavior(menuViewBehavior)

    }
    else {
        var destFrame :CGRect
        if (menuPosition == .left) {
            destFrame = CGRect(x: (shouldOpen) ? -2.0 : -menuWidth-2, y: 0, width: menuWidth, height: height)
        }
        else {
            destFrame = CGRect(x: (shouldOpen) ? width-menuWidth : width+2.0,
                                    y: 0,
                                    width: menuWidth,
                                    height: height)
        }

        UIView.animate(
            withDuration: animationDuration,
            animations: { [weak self] () -> Void in
                self?.sideMenuContainerView.frame = destFrame
            },
            completion: { [weak self] (Bool) -> Void in
                guard let strongSelf = self else { return }
                if (strongSelf.isMenuOpen) {
                    strongSelf.delegate?.sideMenuDidOpen()
                } else {
                    strongSelf.delegate?.sideMenuDidClose()
                }
        })
    }

    if (shouldOpen) {
        delegate?.sideMenuWillOpen()
    } else {
        delegate?.sideMenuWillClose()
    }
}

open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {

    if delegate?.sideMenuShouldOpenSideMenu() == false {
        return false
    }

    if gestureRecognizer is UISwipeGestureRecognizer {
        let swipeGestureRecognizer = gestureRecognizer as! UISwipeGestureRecognizer
        if !allowLeftSwipe {
            if swipeGestureRecognizer.direction == .left {
                return false
            }
        }

        if !allowRightSwipe {
            if swipeGestureRecognizer.direction == .right {
                return false
            }
        }
    }
    else if gestureRecognizer.isEqual(panRecognizer) {
        if allowPanGesture == false {
            return false
        }
        animator.removeAllBehaviors()
        let touchPosition = gestureRecognizer.location(ofTouch: 0, in: sourceView)
        if menuPosition == .left {
            if isMenuOpen {
                if touchPosition.x < menuWidth {
                    return true
                }
            }
            else {
                if touchPosition.x < 25 {
                    return true
                }
            }
        }
        else {
            if isMenuOpen {
                if touchPosition.x > sourceView.frame.width - menuWidth {
                    return true
                }
            }
            else {
                if touchPosition.x > sourceView.frame.width-25 {
                    return true
                }
            }
        }

        return false
    }
    return true
}

@objc internal func handleGesture(_ gesture: UISwipeGestureRecognizer) {
    toggleMenu((menuPosition == .right && gesture.direction == .left)
            || (menuPosition == .left && gesture.direction == .right))
}

@objc internal func handlePan(_ recognizer : UIPanGestureRecognizer){

    let leftToRight = recognizer.velocity(in: recognizer.view).x > 0

    switch recognizer.state {
    case .began:

        break

    case .changed:

        let translation = recognizer.translation(in: sourceView).x
        let xPoint : CGFloat = sideMenuContainerView.center.x + translation + (menuPosition == .left ? 1 : -1) * menuWidth / 2

        if menuPosition == .left {
            if xPoint <= 0 || xPoint > sideMenuContainerView.frame.width {
                return
            }
        }else{
            if xPoint <= sourceView.frame.size.width - menuWidth || xPoint >= sourceView.frame.size.width
            {
                return
            }
        }

        sideMenuContainerView.center.x = sideMenuContainerView.center.x + translation
        recognizer.setTranslation(CGPoint.zero, in: sourceView)

    default:

        let shouldClose = menuPosition == .left ? !leftToRight && sideMenuContainerView.frame.maxX < menuWidth : leftToRight && sideMenuContainerView.frame.minX >  (sourceView.frame.size.width - menuWidth)

        toggleMenu(!shouldClose)

    }
}

fileprivate func updateSideMenuApperanceIfNeeded () {
    if (needUpdateApperance) {
        var frame = sideMenuContainerView.frame
        frame.size.width = menuWidth
        sideMenuContainerView.frame = frame
        sideMenuContainerView.layer.shadowPath = UIBezierPath(rect: sideMenuContainerView.bounds).cgPath

        needUpdateApperance = false
    }
}

/**
Toggles the state of the side menu.
*/
open func toggleMenu () {
    if (isMenuOpen) {
        toggleMenu(false)
    }
    else {
        updateSideMenuApperanceIfNeeded()
        toggleMenu(true)
    }
}
/**
Shows the side menu if the menu is hidden.
*/
open func showSideMenu () {
    if (!isMenuOpen) {
        toggleMenu(true)
    }
}
/**
Hides the side menu if the menu is showed.
*/
open func hideSideMenu () {
    if (isMenuOpen) {
        toggleMenu(false)
    }
}

}

extension ENSideMenu: UIDynamicAnimatorDelegate {
public func dynamicAnimatorDidPause(_ animator: UIDynamicAnimator) {
if (isMenuOpen) {
delegate?.sideMenuDidOpen()
} else {
delegate?.sideMenuDidClose()
}
}
}

from enswiftsidemenu.

evnaz avatar evnaz commented on July 3, 2024

At the moment there is no such possibility.
To hide the side menu you can call hideSideMenuView() function in any view controller.

from enswiftsidemenu.

elsesiy avatar elsesiy commented on July 3, 2024

@smart-technology Shouldn't be too difficult to implement this feature yourself. Just register a tap recognizer in your view controllers which triggers hideSideMenuView(), or am I missing something?

from enswiftsidemenu.

mortenholmgaard avatar mortenholmgaard commented on July 3, 2024

Works great!

from enswiftsidemenu.

lakhshya avatar lakhshya commented on July 3, 2024

@PankovSerge it works fine. Thanks.

from enswiftsidemenu.

jackandjill avatar jackandjill commented on July 3, 2024

@PankovSerge where does your code go in to?

from enswiftsidemenu.

jackandjill avatar jackandjill commented on July 3, 2024

@lakhshya Where did you put this code?

from enswiftsidemenu.

jackandjill avatar jackandjill commented on July 3, 2024

@lakhshya WORKS PERFECT! thankyou.

from enswiftsidemenu.

DagarAmit avatar DagarAmit commented on July 3, 2024

i can't click on item over outterView. I use .removeView method, but its work only one time.
Please give me suggetion

from enswiftsidemenu.

DagarAmit avatar DagarAmit commented on July 3, 2024

Thank you..its WORK!!!

from enswiftsidemenu.

zishanj avatar zishanj commented on July 3, 2024

The solution of @PankovSerge works perfectly. Just in case if you have modified the width of ENSideMenu like sideMenu?.menuWidth = 220, then you have to put

outterView.frame = CGRectMake(sideMenuContainerView.frame.width, 0, sourceView.frame.width - sideMenuContainerView.frame.width,
            sourceView.frame.height)

again in the end of updateFrame() function

from enswiftsidemenu.

 avatar commented on July 3, 2024

Thanks @zishanj !! 👍

from enswiftsidemenu.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.