28

Is there any programatic way to temporarily disable an auto-layout constraint? I do not want that constraint to be considered for a certain period of time at all until I need it again.

TheNotSoWise
  • 869
  • 2
  • 10
  • 15
  • 5
    In 10.10, `NSLayoutConstraint` gains an `active` property that can be set to false to disable it. Setting it to true enable it. – Ken Thomases Sep 24 '14 at 17:52
  • @KenThomases I saw this too, but after I set `active` to `false`, the constraint is not disabled. Is there any sample code for this? I have tried to find some sample or blog about this, I just can't find any. – Joe Huang Dec 21 '15 at 12:50

3 Answers3

44

When developing for iOS 8.0 or later, just use isActive property of NSLayoutConstraint after creating your IBOutlet.

UPDATED

  • to have strong reference to the outlet per below suggestion, thank you @rob mayoff.
  • to use .isActive instead of .active with Swift 4 per below suggestion, thank you @Mohit Singh.

your cell would have the following outlet:

@IBOutlet var photoBottomConstraint: NSLayoutConstraint!

and you would access the constraint in willDisplayCell like:

myCell.photoBottomConstraint.isActive = false

and when you need it again:

myCell.photoBottomConstraint.isActive = true
oyalhi
  • 3,834
  • 4
  • 40
  • 45
  • 30
    If you want to reactivate the constraint later, you probably want to declare the outlet `strong` (or just leave off `weak` since `strong` is the default). When the constraint is deactivated, the views don't reference it anymore, and if you don't have a strong reference to it somewhere, it will be deallocated and the `weak` outlet will be set to nil. – rob mayoff Apr 12 '16 at 01:49
  • 2
    In **Swift 4** `active` has been renamed to `isActive` – Mohit Singh Jan 13 '18 at 12:01
10

Base on oyalhi's answer, also want to point out that you have to make a strong reference to your constraints if you want to make it inactive:

@IBOutlet var photoBottomConstraint: NSLayoutConstraint!

It is not abvious, but if you are using weak reference, photoBottomConstraint could be nil after this call:

myCell.photoBottomConstraint.active = false
Yuchen
  • 30,852
  • 26
  • 164
  • 234
3

You use NSView's removeConstraint:; if you've created the constraint in the interface builder you connect it to the code through an IBOutlet

class MyView : NSView {
    @IBOutlet var temporaryConstraint : NSLayoutConstraint! 

    var constraint : NSLayoutConstraint! = nil /* my strong link */ 
    var constraintShowing : Bool

    func awakeFromNib() {
         constraint = temporaryConstraint
    }

    func toggleLayoutConstraint(sender : AnyObject) -> () {
         if constraintShowing {
             self.removeConstraint( constraint )      
         } else {
             self.addConstraint( constraint )   
         }
         constraintShowing = !constraintShowing
    }
}

Sort of like the dance we used to have to do with NSTableColumns in the 10.4 days before they could be hidden.


You can also do a little controller gadget

class ConstraintController {
    var constraint : NSLayoutConstraint
    var view       : NSView
    var show       : Bool {
        didSet {
            if show {
                view.addConstraint(constraint)
            } else {
                view.removeConstraint(constraint)
            }
        }
    } 

    init (c : NSLayoutConstraint, inView : NSView) {
        constraint = c
        view = inView
        show = true
    }
}

class MyView : NSView {
    @IBOutlet var temporaryConstraint : NSLayoutConstraint!
    var control : ConstraintController? = nil

    func awakeFromNib() -> () { 
        control = ConstraintController(temporaryConstraint, inView: self)
    }

    func show(sender : AnyObject!) -> () {
        control!.show
    }

    func hide(sender : AnyObject!) -> () {
        control!.hide
    }
}

More lines but arguably easier to understand and less hackish.

iluvcapra
  • 9,436
  • 2
  • 30
  • 32
  • So you just keep the reference to the constraint object while removing it from the view? Is there any cleaner way to do it like a .enabled property? – TheNotSoWise Sep 24 '14 at 17:22
  • Heh, I will if I have no choice obviously. Just seems like this is functionality that should already exist. – TheNotSoWise Sep 24 '14 at 17:25
  • 1
    You can also try fiddling with the constraint's live priority but this probably won't work. Depending on what you're doing you might look at NSViewAnimation instead, this usually is how people change view properties on the fly. – iluvcapra Sep 24 '14 at 17:33
  • I tried messing around with the priorities, but it causes a crash for what I am doing. I'll try your initial suggestion. – TheNotSoWise Sep 24 '14 at 17:35
  • 1
    A word of caution. I kept getting errors when using active/deactive, until I changed the priorities on each constraint. – Sean Mar 20 '16 at 08:21