The new NSLayoutConstraint
methods activateConstraints:
and deactivateConstraints:
don\'t appear to work correctly with IB-created con
I faced a similar situation.
I created two sets of NSLayoutConstraints in interface builder. Each set for one case. One set was "installed" the other not.
When I switch the case the coresponding set of layout constraint was activated and the other was deacticated. An as described in the Qusteion rotating forth and back does not work properly.
Is solved this by installing both sets in interface builder. And to get rid of the warnings I used a slighlt lower priority (999) for the second set. This worked for me.
Btw: Strang i used the "installed/not installed" aproach on another viewcontroller, their it worked.
In the not working case the viewcontroller was embedded in a containerview, perhaps that was the reason.
The problem is that you are doing something incoherent with "uninstalled" constraints in the storyboard. They are there but not there. "Uninstalled" constraints are for use only with size classes! You use them if you are going to let Xcode swap constraints for you automatically on rotation. Xcode can't cope with what you're doing. But if you create the second set of constraints in code, everything will work fine.
So, do this. Delete the two "uninstalled" constraints, and delete the uninstalledConstraints
outlet. Now replace your entire view controller code with this:
@property (strong, nonatomic) NSMutableArray *c1;
@property (strong, nonatomic) NSMutableArray *c2;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *installedConstraints;
@property (weak,nonatomic) IBOutlet UIButton *button;
@end
@implementation ViewController {
BOOL did;
}
- (void)viewDidLayoutSubviews {
NSLog(@"did");
if (!did) {
did = YES;
self.c1 = [self.installedConstraints mutableCopy];
self.c2 = [NSMutableArray new];
[self.c2 addObject:
[NSLayoutConstraint constraintWithItem:self.button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopMargin multiplier:1 constant:30]];
[self.c2 addObject:
[NSLayoutConstraint constraintWithItem:self.button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeadingMargin multiplier:1 constant:30]];
}
}
- (IBAction)switchconstraints:(UIButton *)sender {
[NSLayoutConstraint deactivateConstraints:self.c1];
[NSLayoutConstraint activateConstraints:self.c2];
NSMutableArray* temp = self.c1;
self.c1 = self.c2;
self.c2 = temp;
}
Now repeatedly press the button. As you see, it jumps between the two positions. Now rotate the app; the button stays where it is.
You can use this workflow, even though it’s clear that this is not a supported use case currently for the folks at Apple.
The trick is to not uninstall constraints (as @matt also pointed out), but to deactivate them in the viewDidLoad()
of your UIViewController
subclass, before layout occurs (and your conflicting constraints cause a problem).
I’m using that method now and it works perfectly. Ideally, of course, we’d have the ability to visually create groups of constraints and use them like keyframe simply by activating and deactivating them (with free animations in between) :)