Auto Layout

Programmatic Auto Layout

I’ve been digging into using auto layout this weekend. I’m noticing, in our current project, how difficult it is to transition views on an iPad from iOS 7 to iOS 8 on the device and in the simulator.

I think that learning the ins and outs of Auto Layout and Visual Format Language will help me adjust to these issues and hopefully get our team to start focusing on universal layouts for our apps.

An example of using vertical constraints:

UILabel *label = [[UILabel alloc] init];  
label.backgroundColor = [UIColor yellowColor];  
label.font = [UIFont systemFontOfSize:16.0f];  
label.text = @“This is a label.”;  
label.translatesAutoresizingMaskIntoConstraints = NO;  
[self.view addSubview: label];

NSArray *contraints = [NSLayoutConstraint  
   constraintsWithVisualFormat:@“V:|-offsetTop-[label]”
   options:0
   metrics:@{ @“offsetTop” : @100 }
   views:NSDictionaryOfVariableBindings(label)];

[self.view addConstraints:constraints];
  • views: a dictionary of keys for the visual format string. For example, ‘label’ refers to our UILabel named label. NSDictionaryOfVariableBindings creates a dictionary where the keys are the same as the corresponding value’s variable name. metrics: a dictionary of keys and size values to coordinate sizing and positioning in your layout.
  • options: used for specifying alignment attributes such as NSLayoutFormatAlignAllLeft. *format: *V: targets the vertical axis. *| (pipe): reference the superview. *-offsetTop-: puts 100 points (from the metrics dictionary) between the superview and the view that follows. *[label]: defines where our label should appear in the layout.

An example of using horizontal constraints:

UIView *spacer1 = [[UIView alloc] init];  
spacer1.translatesAutoresizingMaskIntoConstraints = NO;  
[self.view addSubview:spacer1];

UIView *spacer2 = [[UIView alloc] init];  
spacer2.translatesAutoresizingMaskIntoConstraints = NO;  
[self.view addSubview:spacer2];

NSArray *constraints = [NSLayoutConstraint  
    constraintsWithVisualFormat:@“H:|[spacer1][label][spacer2(==spacer1)]|”
    options:0
    metrics:nil
    views:NSDictionaryOfVariableBindings(label, spacer1, spacer2)];

[self.view addConstraints:constraints];
Animation with constraints:  
[self.view.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
    if ((constraint.firstItem == label) && (constraint.firstAttribute == NSLayoutAttributeTop)) {
        constraint.constant = 200.0f;
    }
}];

[UIView animateWithDuration:0.5 animations:^{
    [self.view layoutIfNeeded];
}];

Standard Programmatic Layout

Here an example of how we would build out a layout without using the visual format syntax.

An example of using vertical constraints:

@interface ViewController()
@property (nonatomic, strong) NSLayoutConstraint *constraintToAnimate;
@end
…

UILabel *label = [[UILabel alloc] init];  
…
label.translatesAutoresizingMaskIntoConstraints = NO;  
[self.view addSubview:label];

self.constraintToAnimate = [NSLayoutConstraint      constraintWithItem:label  
    attribute:NSLayoutAttributeTop
    relatedBy:NSLayoutRelationEqual
    toItem:self.view
    attribute:NSLayoutAttributeBottom
    multiplier:0.25
    constant:0.0];

[self.view addConstraint:constraintToAnimate];

This example converting into a mathematical equation would look something like this: label.top = superview.bottom * 0.25.

An example of using horizontal constraints:

[self.view addConstraint:[NSLayoutConstraint    
    constraintWithItem:label
    attribute:NSLayoutAttributeCenterX
    relatedBy:NSLayoutRelationEqual
    toItem:self.view
    attribute:NSLayoutAttributeCenterX
    multiplier:1.0
    constant:0.0]];

Here, the label's center point X should be identical to that of its superview.

Animation

Let’s animate the label to a position 50% from the top. Given that NSLayoutConstraint’s multiplier property is read only, we’re forced to remove, redefine, and the re-add it.

[self.view removeConstraint:self.constraintToAnimate];

self.constraintToAnimate = [NSLayoutConstraint  
    constraintWithItem:label
    attribute:NSLayoutAttributeTop
    relatedBy:NSLayoutRelationEqual
    toItem:self.view
    attribute:NSLayoutAttributeBottom
    multiplier:0.5
    constant:0.0];

[self.view addConstraint:self.constraintToAnimate];

[UIView animateWithDuration:0.5 animations:^{
    [self.view layoutIfNeeded];
}];

Comments