Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSLayoutConstraints code to center a view and maintain its aspect ratio

I'd like my subview to be a 16:9 rectangle centered at the top of its superview. In other words, I'd like it to:

  1. be as wide as its superview, but no wider than 400px (UI can rotate to landscape),
  2. be centered horizontally when it's narrower than its superview,
  3. have its top pinned to its superview's top, and
  4. change its height to maintain a 16:9 aspect ratio.

This code almost does it, except I'm having a hard time making horizontal constraints work and not be over or under constrained...

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    UIView *contentView = [[UIView alloc] init];
    contentView.backgroundColor = [UIColor redColor];
    [self.view addSubview:contentView];
    
    contentView.translatesAutoresizingMaskIntoConstraints = NO;
    
    NSDictionary *views = NSDictionaryOfVariableBindings(contentView);
    NSMutableArray *constraints = [NSMutableArray array];

    // this layout string is more like 'wishful coding'.  I don't see why it wouldn't work
    // but clearly this one is the problem
    [constraints addObjectsFromArray:[NSLayoutConstraint
                                      constraintsWithVisualFormat:@"H:|-(>=0)-[contentView(<=400)-(>=0)-]"
                                      options:0 metrics:0 views:views]];
    
    // this centering constraint below almost does the job, but doesn't give me a way
    // to specify width, changing the one above to just @"H:[contentView(<=400)]"
    // doesn't work either
    [constraints addObject:
     [NSLayoutConstraint constraintWithItem:contentView
                                  attribute:NSLayoutAttributeCenterY
                                  relatedBy:NSLayoutRelationEqual
                                     toItem:self.view
                                  attribute:NSLayoutAttributeCenterY
                                 multiplier:1.f constant:0.f]];

    // 9:16 works fine, I think
    [constraints addObject:
     [NSLayoutConstraint constraintWithItem:contentView
                                  attribute:NSLayoutAttributeHeight
                                  relatedBy:NSLayoutRelationEqual
                                     toItem:contentView attribute:NSLayoutAttributeWidth
                                 multiplier:9.0/16.0 constant:0.0]];
    
    // pin the tops works fine, I think
    [constraints addObjectsFromArray:
     [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView]"
                                             options:0 metrics:0 views:views]];

    [self.view addConstraints:constraints];
}
like image 342
danh Avatar asked Aug 14 '13 03:08

danh


1 Answers

If you want to center the red box horizontally, then you want to equate the views' CenterX, not CenterY. So that constraint should look like this:

[NSLayoutConstraint constraintWithItem:contentView
                             attribute:NSLayoutAttributeCenterX
                             relatedBy:NSLayoutRelationEqual
                                toItem:self.view
                             attribute:NSLayoutAttributeCenterX
                            multiplier:1.f constant:0.f]];

Then on the first constraints, the constraints you have there are ambiguous since there is more than one way to satisfy >=0 margin on each side and <=400 in width. A better way would be to say exactly what you said in your question, which is that you need the width to be <=400 and you would like the margins to be 0 if possible.

So something like this:

[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0@900)-[contentView(<=400)]-(0@900)-|"
                                        options:0 metrics:0 views:views]];

I believe that gets you want you want?

like image 129
Firoze Lafeer Avatar answered Oct 30 '22 23:10

Firoze Lafeer