0

I'am trying to make a side menu and i have some problems with setting it with auto layout. I have a rootViewController that i add to it the leftMenuVC as childVC then i set the constraints.

class RootVC: UIViewController, NavigationBarDelegate {
    var leftMenuVC: UIViewController?
    var navigationBar = NavigationBar()
    var isMenuCollapsed = true

    override func viewDidLoad() {
        leftMenuVC = leftVC()
        addChildViewController(leftMenuVC!)
        view.addSubview(leftMenuVC!.view)
        leftMenuVC!.didMove(toParentViewController: self)
    }

    override func viewDidLayoutSubviews() {
        if let v = leftMenuVC?.view {
            v.translatesAutoresizingMaskIntoConstraints = false
            v.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
            v.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
            v.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -140).isActive = true
            v.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        }
    }

    func menuButtonClicked(){

    }
}

So my question is how to change constraints to hide/show the menu with support of orientations

Chikiadel
  • 600
  • 5
  • 8

2 Answers2

0

What I usually do when I want to hide a view outside the screen with constraints is:

1 Set all constraints so that the sideview is visible (in active state)

2 Keep in reference the constraint that stick your sideview on one side (here the left one)

leftAnchor = NSLayoutConstraint(item: v, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0)
view.addConstraint(leftAnchor)
view.addConstraint(NSLayoutConstraint(item: v, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: v, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: v, attribute: .width, relatedBy: .equal, toItem: view, attribute: .width, multiplier: 0.6, constant: 0))

3 Set one more constraint so that the view will be hidden. Usually it's something like that. Note that the priority is set to 999 to avoid constraint conflicts.

var hiddingConstraint = NSLayoutConstraint(item: v, attribute: .right, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0)
hiddingConstraint.priority = 999
view.addConstraint(hiddingConstraint)

4 Animate by activating or not your leftAnchor

UIView.animate(withDuration: 0.3) {
       self.leftAnchor.active = false
       self.view.layoutIfNeeded()
}

So you should end up with a code like this:

class RootVC: UIViewController, NavigationBarDelegate {
    var leftMenuVC: UIViewController?
    var navigationBar = NavigationBar()
    var isMenuCollapsed = true {
        didSet {
            UIView.animate(withDuration: 0.3) {
                self.leftAnchor?.isActive = self.isMenuCollapsed
                self.view.layoutIfNeeded()
            }
        }

    }
    var leftAnchor : NSLayoutConstraint?

    override func viewDidLoad() {
        leftMenuVC = leftVC()
        addChildViewController(leftMenuVC!)
        view.addSubview(leftMenuVC!.view)
        leftMenuVC!.didMove(toParentViewController: self)
    }

    override func viewDidLayoutSubviews() {
        if let v = leftMenuVC?.view {

            leftAnchor = NSLayoutConstraint(item: v, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0)
            view.addConstraint(leftAnchor!)
            view.addConstraint(NSLayoutConstraint(item: v, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0))
            view.addConstraint(NSLayoutConstraint(item: v, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0))
            view.addConstraint(NSLayoutConstraint(item: v, attribute: .width, relatedBy: .equal, toItem: view, attribute: .width, multiplier: 0.6, constant: 0))

            var hiddingConstraint = NSLayoutConstraint(item: v, attribute: .right, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0)
            hiddingConstraint.priority = 999
            view.addConstraint(hiddingConstraint)
        }
    }

    func menuButtonClicked(){
        isMenuCollapsed = !isMenuCollapsed
    }
}

PS: I won't put the constraints setting in viewDidLayoutSubviews, maybe in viewWillAppear, as you don't have to set them every time the device is being rotated. That's the purpose of constraints

RomOne
  • 2,065
  • 17
  • 29
  • Thank you RomOne, this works pretty good, i guess my error is that i have't low down the priority of the seconde constraint. keep in mind that you have set translatesAutoresizingMaskIntoConstraints = false – Chikiadel Mar 30 '18 at 10:39
0

Instead of writing this code by yourself, save yourself the trouble. Here is MMDrawerController to your rescue. I am using it myself. It's super easy to implement and offers lots of customization options. Hope you find it useful. :-)

Zahurafzal Mirza
  • 290
  • 1
  • 15