108

I have used auto layout for my view controllers. I have set the V and H positions in constraints, but I want to know how can I increase my button size when it changes to 5s, 6 and 6 Plus. This is the way I added constraints for the login button:

NSArray *btncon_V=[NSLayoutConstraint constraintsWithVisualFormat:@"V:[btnLogin(40)]" options:0 metrics:nil views:viewsDictionary];
[btnLogin addConstraints:btncon_V];

NSArray *btncon_POS_H=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-100-[btnLogin]-100-|" options:0 metrics:nil views:viewsDictionary];
[self.view addConstraints:btncon_POS_H];


NSArray *btncon_POS_V=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-70-[Title]-130-[lblFirst]-0-[lblSecond]-20-[textusername]-10-[txtpassword]-10-[btnLogin]" options:0 metrics:nil views:viewsDictionary];

[self.view addConstraints:btncon_POS_V];

But my problem is that while it manages the left and right side gap, it's getting stretched in iPhone 6 and 6 Plus since the height is fixed. How can I increase the size according to the screen size? I think this might be the aspect ratio, but how can I set the aspect ratio constraint in code?

2

7 Answers 7

127

Layout Anchors is the most convenient way to set constraints programmatically.

Say you want to set 5:1 aspect ratio for your button then you should use:

button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0/5.0).isActive = true

Here's the full code:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = UIButton(type: .custom)
        button.setTitle("Login", for: .normal)
        button.backgroundColor = UIColor.darkGray

        self.view.addSubview(button)

        button.translatesAutoresizingMaskIntoConstraints = false

        let margins = view.layoutMarginsGuide

        button.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 20.0).isActive = true
        button.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: -20.0).isActive = true
        button.bottomAnchor.constraint(equalTo: margins.bottomAnchor, constant: -20.0).isActive = true
        button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0/5.0).isActive = true
    }

}

Here're results achieved with code written above. You can see that button keeps its 5:1 aspect ratio across various devices:

Result view

Sign up to request clarification or add additional context in comments.

1 Comment

Great answer. This is actually not 5:1, but 1:5 aspect ratio :)
90

Like this. Try once.

[self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.yourview addConstraint:[NSLayoutConstraint
                                  constraintWithItem:self.yourview
                                  attribute:NSLayoutAttributeHeight
                                  relatedBy:NSLayoutRelationEqual
                                  toItem:self.yourview
                                  attribute:NSLayoutAttributeWidth
                                  multiplier:(self.yourview.frame.size.height / self.yourview.frame.size.width)
                                  constant:0]];

or in the place of (self.yourview.frame.size.height / self.yourview.frame.size.width) you can use any float value. Thanks.

Swift 3.0 -

self.yourview!.translatesAutoresizingMaskIntoConstraints = false
self.yourview!.addConstraint(NSLayoutConstraint(item: self.yourview!,
                                          attribute: NSLayoutAttribute.height,
                                          relatedBy: NSLayoutRelation.equal,
                                          toItem: self.yourview!,
                                          attribute: NSLayoutAttribute.width,
                                          multiplier: self.yourview.frame.size.height / self.yourview.frame.size.width,
                                          constant: 0))

10 Comments

Its giving me this error Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Multiplier is not finite! That's illegal. multiplier:nan'
it means in the scenario like if height is 100 and width is 200 and you given multiplier 0.5 with my code, then if your height will increase to 150 by changing any other constraint then width will automatically increase to 300. But to do this you need to increase one constraint of the view like width or height.
it will take height:width = 1:2 that is 0.5.
Don't forget to add this line before setting any constraints programatically: [self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
When using constraints, my frame sizes were all zero. To get the aspect ratio, instead, I used self.yourview.intrinsicContentSize
|
21

Swift 3:

yourView.addConstraint(NSLayoutConstraint(item: yourView,
                                          attribute: .height,
                                          relatedBy: .equal,
                                          toItem: yourView,
                                          attribute: .width,
                                          multiplier: 9.0 / 16.0,
                                          constant: 0))

2 Comments

For iOS 8 and above you should be using the isActive property of NSLayoutConstraint instead of calling addConstraint(:). aspectRatioConstraint.isActive = true
Why don't you use .width as the first attribute? The result is attr2 * multiplier , the aspect ratio is width / height, so width = height * aspectRatio, if we put the .height to the first attribute and the aspectRatio to the multiplier then the result is totally reversed.
20

Helper Extension on UIView

extension UIView {
    
    func aspectRatio(_ ratio: CGFloat) -> NSLayoutConstraint {
        
        return NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: self, attribute: .width, multiplier: ratio, constant: 0)
    }
}

And usage is:

view.aspectRatio(1.0/1.0).isActive = true

2 Comments

and usage: view.aspectRation(1.0/1.0)
This is indeed an elegant solution barring couple of types: 1. The toItem parameter is set to .self instead of self 2. And the usage in comment should be view.aspectRation(1.0/1.0).isActive = true I tested this in Xcode 10.2.1 Swift 5.
19

You can set "Height constraint" at Design-time in Interface Builder. Just check '"Remove at build time", and it removes when App will running.

enter image description here After that you can add "Aspect Ratio" constraint, for example, in viewDidLoad method.

In Xamain.iOS for "16:9" it's looks like this:

    this.ImageOfTheDay.AddConstraint(NSLayoutConstraint.Create(
            this.ImageOfTheDay,
            NSLayoutAttribute.Height,
            NSLayoutRelation.Equal,
            this.ImageOfTheDay,
            NSLayoutAttribute.Width,
            9.0f / 16.0f,
            0));

Or, as Mahesh Agrawal said:

    [self.ImageOfTheDay addConstraint:[NSLayoutConstraint
                              constraintWithItem:self.ImageOfTheDay
                              attribute:NSLayoutAttributeHeight
                              relatedBy:NSLayoutRelationEqual
                              toItem:self.ImageOfTheDay
                              attribute:NSLayoutAttributeWidth
                              multiplier:(9.0f / 16.0f)
                              constant:0]];

Comments

6

Swift 5 solution, Xcode 12.4. Requires ios 9.0+

Simply anchor your height constraint to a certain ratio:

let aspectRatio: CGFloat = 9 / 16 // Example of ratio you want to apply
yourView.heightAnchor.constraint(equalTo: imageView.widthAnchor,
                                 multiplier: aspectRatio).isActive = true

Comments

5

I have try all answers above but didn't work, and this is my solution with swift 3:

let newConstraint = NSLayoutConstraint(item: yourView, attribute: .width, relatedBy: .equal, toItem: yourView, attribute: .height, multiplier: 560.0/315.0, constant: 0)
yourView.addConstraint(newConstraint)
NSLayoutConstraint.activate([newConstraint])  
NSLayoutConstraint.deactivate(yourView.constraints)
yourView.layoutIfNeeded()

1 Comment

You should always deactivate (potentially conflicting) constraints before adding new ones to avoid autolayout errors

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.