9

In my particular case I have view inside the view controller for which I added the following constraints:

  • Set leading, trailing, top and bottom edges to 0
  • Set multiplier to bottom edge to 2:1

Now the view sits in the top half on the view controller.

Inside this I add a square image view, for which I added the following constraints:

  • Ctrl drag from image view to superview and added equal heights and widths.
  • Change the multiplier for width and height until I have a perfect square.
  • Added constraints to be center vertically and horizontally

My constraints seems perfect, but when running in the simulator I don't get a perfect square. Besides this, the image view doesn't get resize when running on different simulator screens.

This is my setup:

  • Auto layout and size classes are enabled
  • I use an Inferred size for the storyboard
  • Adaptive layout is set to Any for width and height
  • I am trying to run this for the 4s,5,6 and 6+ simulators.

I looked on other stackoverflow posts, but nothing seems to work.

Are there some basic steps to do this ?

enter image description here

edit:

After setting >=10 constraints:

enter image description here

edit 3: I added top,bottom,leading,trailing constraints 2 times, 1 with lower than or equal(priority 1000), the other one with greater than or equal(priority 800) with the constant value of 90. I don't know why for bottom it tries to streches to 90 pt from the main view, not the container view(green one).

enter image description here

2
  • 2
    You should use an aspectRatio constraint of 1:1 on the view you want to remain square and then contain just either it's height or its width to it's parent, but not both. Commented Aug 19, 2015 at 15:42
  • so just set the aspect ratio of 1:1 and set the height or witdh proportional to the superview ? Doing that I get a square (which is to small) but it doesn't resize depending on the screen, same size on all screen's Commented Aug 19, 2015 at 21:05

4 Answers 4

26
+100

You have a view that needs to expand to fill its container while maintaining its aspect ratio. This is a common pattern with Auto Layout.

The trick is to use two constraints for leading/trailing/top/bottom:

  • =10 at low priority

  • >=10 at required priority.

Putting it all together, you have:

  • Aspect Ratio 1:1

  • Center X/Y in Superview

  • Leading/Trailing/Top/Bottom to Superview = 10 (at 750 priority)

  • Leading/Trailing/Top/Bottom to Superview >= 10 (at 1000 priority)

There are also a couple of things to consider with UIImageView:

  • UIImageView will have an intrinsic content size based on the image that it is displaying, so you'll want to ensure that its Content Hugging Priority is lower than the 750 priority you use for the =10 constraints.

  • UIImageView.contentMode determines how the underlying image is sized relative to the size of the UIImageView. By default, it's set to UIViewContentModeScaleToFill.

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

4 Comments

It works, but I do have a question. On the 4s the square looks too small, can I control this somehow ? On the 6 and 5s screen the dimensions are ok.
@Adrian You can use a minimum height constraint on the image's superview. E.g.: height=superview.height*0.5 @ priority 900, height >= 350 @ priority 1000
@darren that worked thanks. I have to introduce 1 new constraint like Img.height = 0.25 x superview.height@900 to increase the size of the image propotionally x 0.25 muliplier as the image was growing size drastically from iPhone 6 to 6 Plus.
how to add all of this Leading/Trailing/Top/Bottom to Superview ?
3
container view
----------------------------------------------
|                     |                      |
|                    >=10                    |
|        imageView    |                      |
|        ----------------------------        |
|        |            |             |        |      
|        |            |             |        |
|        |            |             |        |
|        |            |             |        |
|        |            |             |        |
|- >=10 -|---------- 1:1 -----------|- >=10 -|
|        |            |             |        |
|        |            |             |        |
|        |            |             |        |
|        |            |             |        |
|        ----------------------------        |
|                     |                      |
|                    >=10                    |
|                     |                      |
----------------------------------------------

**If you want you can specify the imageView's height or width as well with a lower priority constraint.

4 Comments

Can you tell me how exactly do you set that constraints ? I just add a leading, trailing, bottom and top constraints and choose greater than or equal and set the constant to 10 or how ?
Yes, it's just like you say, then add a 1:1 aspect ratio to the image (cntrl+drag) the image to itself.
It doesn't work for me. I attached a screenshot to see how it looks.
How would you translate this programatically? @DannyBravo
2

I had success using this configuration.

  1. What I did was first add constraints for center X. (Ignore the center Y one even though it's in my screenshot. It will break regardless because of step 2.)

  2. Then I added a top and bottom constraint

  3. Finally I added a aspect ratio constraint

When I animated this, the box scaled as a square correctly. If you want I can upload the Test project.

enter image description here

Comments

1

In code, for realz. Note: the weird CGFloat.greatestFiniteMagnitude is necessary (or some larger number anyway) to get the other constraints to pick up. Enjoy.

extension UIView {
    func constrainAsSquare(container: UIView, multiplier: CGFloat) {
        translatesAutoresizingMaskIntoConstraints = false

        centerXAnchor.constraint(equalTo: container.centerXAnchor).isActive = true
        centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true

        widthAnchor.constraint(equalToConstant: .greatestFiniteMagnitude).activate(with: .defaultLow)

        heightAnchor.constraint(lessThanOrEqualTo: container.heightAnchor, multiplier: multiplier).activate(with: .defaultHigh)
        widthAnchor.constraint(lessThanOrEqualTo: container.widthAnchor, multiplier: multiplier).activate(with: .defaultHigh)

        widthAnchor.constraint(equalTo: heightAnchor).activate(with: .required)
    }
}

extension NSLayoutConstraint {
    @discardableResult
    func activate(with priority: UILayoutPriority) -> NSLayoutConstraint {
        self.priority = priority
        isActive = true
        return self
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.