Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change Autolayout at runtime

Is it possible to change autolayout constraints during runtime?

I know you can change the constant, but how would you change different attributes.

For example, NSLayoutAttributeTop to NSLayoutAttributeBottom?

Here is a simple sample of what I hope to achieve, it will set a label top left, then when you press a button it will set the label bottom right.

The initial constraints work as expected, tapping the button doesn't work as expected and throws the infamous "Unable to simultaneously satisfy constraints."

Here is the code I am using:

    - (void)viewDidLoad
{
    [super viewDidLoad];
    [self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
    self.constraintA = [NSLayoutConstraint constraintWithItem:self.topLabel
                                                    attribute:NSLayoutAttributeTop
                                                    relatedBy:NSLayoutRelationEqual
                                                       toItem:self.view
                                                    attribute:NSLayoutAttributeTop
                                                   multiplier:1.0
                                                     constant:0.0];

    self.constraintB = [NSLayoutConstraint constraintWithItem:self.topLabel
                                                    attribute:NSLayoutAttributeLeft
                                                    relatedBy:NSLayoutRelationEqual
                                                       toItem:self.view
                                                    attribute:NSLayoutAttributeLeft
                                                   multiplier:1.0
                                                     constant:0.0];

    [self.view addConstraint:self.constraintA];
    [self.view addConstraint:self.constraintB];
}

- (IBAction)tappedChange:(id)sender
{

    [self.view removeConstraints:@[ self.constraintA, self.constraintB ]];

    self.constraintA = [NSLayoutConstraint constraintWithItem:self.topLabel
                                                    attribute:NSLayoutAttributeBottom
                                                    relatedBy:NSLayoutRelationEqual
                                                       toItem:self.view
                                                    attribute:NSLayoutAttributeBottom
                                                   multiplier:1.0
                                                     constant:0.0];

    self.constraintB = [NSLayoutConstraint constraintWithItem:self.topLabel
                                                    attribute:NSLayoutAttributeRight
                                                    relatedBy:NSLayoutRelationEqual
                                                       toItem:self.view
                                                    attribute:NSLayoutAttributeRight
                                                   multiplier:1.0
                                                     constant:0.0];
    [self.view addConstraint:self.constraintA];
    [self.view addConstraint:self.constraintB];
    [self.view setNeedsLayout];
}

Thank you for your time.

like image 969
Buyin Brian Avatar asked Nov 12 '15 22:11

Buyin Brian


1 Answers

You only need to perform the Remove/Recreate/Add constraint dance on iOS 7 and below. If you are writing for a modern iOS (8 and above) you can create all your constraints at once and then just set the .active property on whatever NSLayoutConstraint instance you want at any given time.

// Move to right
self.leadingConstraint.active = false;
self.trailingConstraint.active = true;

// Move to bottom
self.topConstraint.active = false;
self.bottomConstraint.active = true;

If you are using Interface Builder you can create all the constraints that will be needed (note the grayed out constraints that aren't active by default).

Xcode Window Showing Example

Then when the button is pressed you can deactivate the old constraints and activate the new ones.

If you are ever unsure about the views being shown you can pause the app execution and use the following private API in the debugger to print out a full list of views and constraints:

po [[UIWindow keyWindow] _autolayoutTrace]
like image 71
Steven Hepting Avatar answered Oct 28 '22 09:10

Steven Hepting