Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

activateConstraints: and deactivateConstraints: not persisting after rotation for constraints created in IB

The new NSLayoutConstraint methods activateConstraints: and deactivateConstraints: don't appear to work correctly with IB-created constraints (they do work correctly for code-created constraints). I created a simple test app with one button that has two sets of constraints. One set, which is installed, has centerX and centerY constraints, and the other set, which is uninstalled, has top and left constraints (constant 10). The button method switches these constraints sets. Here is the code,

@interface ViewController () @property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *uninstalledConstraints; @property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *installedConstraints; @end  @implementation ViewController   - (IBAction)switchconstraints:(UIButton *)sender {     [NSLayoutConstraint deactivateConstraints:self.installedConstraints];     [NSLayoutConstraint activateConstraints:self.uninstalledConstraints]; }   -(void)viewWillLayoutSubviews {     NSLog(@"installed: %@    uninstalled: %@", ((NSLayoutConstraint *)self.installedConstraints[0]).active ? @"Active" : @"Inactive", ((NSLayoutConstraint *)self.uninstalledConstraints[0]).active ? @"Active" : @"Inactive");  } 

When the app launches, the button is in the correct, centered position defined by its installed constraints. After I do the activation/inactivation in the button's action method, the button moves to its new position correctly, but when I rotate the view to landscape, it moves back to its initially defined position (though a log still shows the newly activated set as being active). When I rotate back to portrait, the button stays in its initial position (centered in the screen), and now the log shows that initial set of constraints as active, and the ones I activated, as inactive.

The question is, is this a bug, or are these methods not supposed to work in this way with IB defined constraints?

like image 262
rdelmar Avatar asked Dec 27 '14 00:12

rdelmar


2 Answers

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.

like image 120
matt Avatar answered Oct 01 '22 01:10

matt


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.

like image 28
Christian1313 Avatar answered Oct 01 '22 02:10

Christian1313