35

I have a simple (I think) problem: I have a UIImageView, which I have set multiple constraints for in the storyboard.

At times, I'll need to disable the constraints, and set its frame manually, but later, I'll want to re-enable those constraints and have the view return to where it was as decided by the constraints.

I thought I could do this with something like:

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var constraint: NSLayoutConstraint!

func example() { 

    //to set its location and size manually
    imageView.removeConstraint(constraint) 
    imageView.frame = CGRectMake(...)

    //to cause it to return to its original position
    imageView.addConstraint(constraint) 

}

With this, however, I get the error 2015-08-26 01:14:55.417 Constraints[18472:923024] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7fbb72815f90 V:[_UILayoutGuide:0x7fbb72814c20]-(100)-[UIImageView:0x7fbb72814540]>. Does anyone know why this error occurs?

Adding the constraints instead to view by calling self.view.addConstraint(...) gets rid of the error, but still doesn't bring the image view back to where it should be.

I notice I don't even have to remove nor deactivate constraints to be able to set the frame of the imageView without problem, so long as I don't call setTranslatesAutoresizingMaskIntoConstraints(true).

I've already seen this question, but the answer seems unnecessarily complicated, perhaps outdated, and even inapplicable.

I also saw this question, but this doesn't cover constraints can be re-enabled—only how they can be disabled.

Trying to set the active property:

self.top.active = false
self.right.active = false
self.bottom.active = false
self.left.active = false
    
imageView.frame = CGRectMake(100, 100, 100, 100)

This actually just results in imageView being no longer visible. (If I don't set all the constraints' active property to false, however, imageView moves to the proper position.

The real problem, though, is that when I try to have the image view return to where it was, by setting all the constraints' active property to true, nothing happens—the imageView stays where it was (in this case as specified by imageView.frame = CGRectMake(100, 100, 100, 100).

Also, it seems, according to my testing and Joachim Bøggild's answer here, that when a constraint's active property is set to false, that constraint becomes nil, and thus cannot be re-activated.

Adding constraints to an array and activating/deactivating them:

Interestingly, this causes almost exactly the same issues as setting the active property. Placing all the constraints in an array array, then calling NSLayoutConstraint.deactivateConstraints(array) makes the image view disappear. Also, re-activating the constraints later with NSLayoutConstraint.activateConstraints(array) doesn't have the image view return to where it should—it stays where it was.

Community
  • 1
  • 1
Randoms
  • 2,110
  • 2
  • 20
  • 31

3 Answers3

71

Aha!

Constraints become nil (and thus can't be reactivated), once their active property is set to false. Making them strong references (thanks, Caleb, for clearing up the nomenclature) preserves them so they can be activated and deactivated as desired.

Randoms
  • 2,110
  • 2
  • 20
  • 31
  • 2
    If anybody is wondering how to make an `IBOutlet` strong: just remove the `weak` keyword, and voila: your reference is strong! – LinusGeffarth Apr 18 '18 at 17:36
35

If you look at the docs for NSLayoutConstraint you'll find a section called Activating and Deactivating Constraints that describes the active property, which in turn tells you:

You can activate or deactivate a constraint by changing this property...Activating or deactivating the constraint calls addConstraint: and removeConstraint: on the view that is the closest common ancestor of the items managed by this constraint. Use this property instead of calling addConstraint: or removeConstraint: directly.

So, once you've got a strong reference to the constraint in question (such as you have with your outlet), you can simply set it's active property to false (or NO in Obj-C) to disable, or true (or YES) to enable.

Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
Caleb
  • 124,013
  • 19
  • 183
  • 272
  • Hi Caleb, thanks for your input! I tried this, but ran into a few issues, which I described in an edit above. – Randoms Aug 26 '15 at 20:31
  • 2
    It also seems that when a constraint's `active` is set to false, that constraint becomes nil and thus cannot be reactivated. – Randoms Aug 27 '15 at 02:42
  • 5
    Ah, got it. Making the outlets for the constraints strongly typed fixed it—I can now activate and deactivate them properly. – Randoms Aug 27 '15 at 04:10
  • 3
    Strong references, not strongly typed. That makes sense, because the docs say that changing the `active` property removes the constraint, which means that the view the constraint was attached to no longer does. With no strong references, the constraint would be deallocated. Making your outlet strong avoids that. – Caleb Aug 27 '15 at 12:28
  • 6
    @Randoms making outlets to be `strong` is actually the correct answer, at least it was my problem. You should post it as an answer, rather that as a comment that's hard to find. Or update it as part of the question itself. – i4niac Dec 05 '15 at 03:01
  • @i4niac Fixed :D – Iulian Onofrei Mar 29 '17 at 13:16
1

Connect Constraint as IBOutlet from storyboard to ViewController and create an Array add All constraint in array.

Deactivate those Constraint when not in uses.

Add constraint whenever in uses.

NSLayoutConstraint *constraint1;
NSLayoutConstraint *constraint2;
NSLayoutConstraint *constraint3;
NSArray *arr = @[constraint1,constraint2,constraint3];
 [NSLayoutConstraint deactivateConstraints:arr];

//After deactivate constraint array add what ever frame you want to add

//Activate  lateroN
[NSLayoutConstraint activateConstraints:arr];
Kavita
  • 176
  • 8
  • Hi Kavita Asija, I tried this too, well, a Swift-rendition of it, and ran into some issues, which I added in an edit above. – Randoms Aug 26 '15 at 20:38
  • - (void)updateConstraintsIfNeeded - (void)updateConstraints - (BOOL)needsUpdateConstraints - (void)setNeedsUpdateConstraints Update View Constraints after apply active and deactivate Constraints.. – Kavita Aug 27 '15 at 02:53