AutoLayout: Vertically centering two UIViews in a superview that can resize

13,026

Solution 1

This is so trivial to do in IB.

1) ⌃ drag from button1 to top. select "center horizontally in container".

2) ⌃ drag from button1 to left. select "center vertically in container".

3) do the same with button2.

4) now the only thing left to do is size the buttons because this is what it looks like.

enter image description here

This is also very trivial.

5) ⌃ drag from button1 to the left. select "leading space to container margin".

6) ⌃ drag from button1 to the right. select "trailing space to container margin".

7) do the exact same thing with button2.

The finished product, looks like this (NB I didn't quite center them, but I could have easily enough):

enter image description here

enter image description here

Solution 2

The simplest way to vertically center is to add a NSLayoutAttributeCenterY constraint - preferably to the element that is near the center of the view. And if all views have a vertical spacing constraints, then they will all be centred. No need to muck with the view hierarchy or add spacer views.

[self.view addConstraint:
    [NSLayoutConstraint constraintWithItem:button2 
                                 attribute:NSLayoutAttributeCenterY
                                 relatedBy:NSLayoutRelationEqual 
                                    toItem:self.view 
                                 attribute:NSLayoutAttributeCenterY 
                                multiplier:1.0 
                                  constant:0]];

If you need to adjust the positioning, set the constant. For example: constant:-30 will move it up 30 points.

You can also anchor elements based on different logical areas of the view. For example, if you wanted to anchor your first button at 25% of the view height, you can set the multiplier to 0.5.

Solution 3

Agreed with rdelmar. Here's another option if you want to preserve view hierarchy.

You are currently spacing the buttons at the top and bottom using constraints. Instead, create two empty UIViews, they will be used as spacers. They should be positioned one at the top and one at the bottom of your buttons. Using autolayout constraints, make sure that the height of these two spacer views is always equal. Make sure they are pinned to the top and bottom of the buttons and the top and bottom of the superview, respectively.

In VFL: V:|-[spacer1(==spacer2)]-[button1]-(20)-[button2]-[spacer2(==spacer1)]-|.

You may have to do this in code, I'm not sure if IB can do this.

Solution 4

One way to accomplish this is to enclose the two buttons in another UIView, and center that view in the controller's view. Give the buttons a fixed distance to the top and bottom of this view, and either a fixed distance between them, or a fixed height for the view.

Share:
13,026

Related videos on Youtube

Jamie Forrest
Author by

Jamie Forrest

Updated on June 21, 2022

Comments

  • Jamie Forrest
    Jamie Forrest almost 2 years

    I have two UIButtons, one on top of the other, in a superview whose height can be resized. The two buttons should have a constant vertical spacing between them, but the top and bottom spacing should resize so that the two buttons stay centered in the superview as it resizes.

    I tried creating two less-than-or-equal constraints (with equal priority) on the spacing to the superview for each button, as well as a constant vertical spacing between the buttons, as shown below: enter image description here

    (The reason why it's less-than-or-equal here is because this view is defined at the given height in IB for 4" screens, but can be shrunk for 3.5" screens.) However, this doesn't do the trick, as you can see from the screenshot while the app is running: enter image description here

    It's almost as if you want to be able to tell AutoLayout that the two constraints themselves should have equal values, even if they are both set to "less-than-or-equal". Is there any way to do what I'm trying to do, or perhaps a better way?

    • race_carr
      race_carr almost 11 years
      Are you using Storyboards or Interface Builder?
    • Jamie Forrest
      Jamie Forrest almost 11 years
      Storyboards within IB.
  • Jamie Forrest
    Jamie Forrest almost 11 years
    I tried doing this as well but couldn't get it to work. In any case it seems like you should be able to do what I'm trying to do without wrapping everything in another UIView.
  • rdelmar
    rdelmar almost 11 years
    @JamieForrest, I don't think it's easy to do without wrapping it in another view. I did it simply by dragging two buttons onto a controller's view, selecting them both, embed in UIView (from the menu), and then centering that view. How did you try to do it, and what result did you get?
  • ninjaneer
    ninjaneer about 8 years
    Isn't the whole point of Autolayout is so that we don't need to encapsulate views into a container view?
  • garrettmurray
    garrettmurray about 7 years
    This accepted answer is not accurate. The first section, in which the author says to simply add centerX and centerY constraints, will NOT result in the visuals shown in the screenshots that follow. If you set two UIViews to the same centerX and Y they will be z-index stacked. Accurate screenshots would show them as a single button. Beware.
  • SmileBot
    SmileBot about 7 years
    @garrettmurray drag the buttons to where you want then do the steps. You may need to update constraints as well. This teaches you how to use centering constraints which will adjust correctly to changes in orientation. I'm assuming a bit of very basic knowledge of autolayout in my answer.
  • Dbl
    Dbl almost 7 years
    @JasonMoore "Describe layouting with ios in two short sentences"