Evenly space multiple views within a container view

Auto Layout is making my life difficult. In theory, it was going to be really useful when I switched, but I seem to fight it all of the time.

I’ve made a demo project to try to find help. Does anyone know how to make the spaces between views increase or decrease evenly whenever the view is resized?

  • Change Spacing Between UIBarButtonItems in iOS 8
  • Decrease Space between UICollectionViewCells
  • How to adjust space between two UIBarButtonItem in rightBarButtonItems
  • XCode alignment/spacing between Storyboard and Simulator?
  • iOS - UICollectionView spacing still there when set to 0 - How to set with no spacing between cells
  • How to change an UILabel/UIFont's letter spacing?
  • Here are three labels (manually spaced vertically even):

    image1

    What I want is for them to resize their spacing (not the view size) evenly when I rotate. By default, the top and bottom views squish towards the center:

    image2

    27 Solutions Collect From Internet About “Evenly space multiple views within a container view”

    So my approach allows you to do this in interface builder. What you do is create ‘spacer views’ that you have set to match heights equally. Then add top and bottom constraints to the labels (see the screenshot).

    enter image description here

    More specifically, I have a top constraint on ‘Spacer View 1’ to superview with a height constraint of lower priority than 1000 and with Height Equals to all of the other ‘spacer views’. ‘Spacer View 4’ has a bottom space constraint to superview. Each label has a respective top and bottom constraints to its nearest ‘spacer views’.

    Note: Be sure you DON’T have extra top/bottom space constraints on your labels to superview; just the ones to the ‘space views’. This will be satisfiable since the top and bottom constraints are on ‘Space View 1’ and ‘Spacer View 4’ respectively.

    Duh 1: I duplicated my view and merely put it in landscape mode so you could see that it worked.

    Duh 2: The ‘spacer views’ could have been transparent.

    Duh 3: This approach could be applied horizontally.

    LOOK, NO SPACERS!

    Based on suggestions in the comments section of my original answer, especially @Rivera’s helpful suggestions, I’ve simplified my original answer.

    I’m using gifs to illustrate just how simple this is. I hope you find the gifs helpful. Just in case you have a problem with gifs, I’ve included the old answer below with plain screen shots.

    Instructions:

    1) Add your buttons or labels. I’m using 3 buttons.

    2) Add a center x constraint from each button to the superview:

    enter image description here

    3) Add a constraint from each button to the bottom layout constraint:

    enter image description here

    4) Adjust the constraint added in #3 above as follows:

    a) select the constraint,
    b) remove the constant (set to 0),
    c) change the multiplier as follows: take the number of buttons + 1, and starting at the top, set the multiplier as buttonCountPlus1:1, and then buttonCountPlus1:2, and finally buttonCountPlus1:3. (I explain where I got this formula from in the old answer below, if you’re interested).

    enter image description here

    5) Here’s a demo running!

    enter image description here

    Note: If your buttons have larger heights then you will need to compensate for this in the constant value since the constraint is from the bottom of the button.


    Old Answer


    Despite what Apple’s docs and Erica Sadun’s excellent book (Auto Layout Demystified) say, it is possible to evenly space views without spacers. This is very simple to do in IB and in code for any number of elements you wish to space evenly. All you need is a math formula called the “section formula”. It’s simpler to do than it is to explain. I’ll do my best by demonstrating it in IB, but it’s just as easy to do in code.

    In the example in question, you would

    1) start by setting each label to have a center constraint. This is very simple to do. Just control drag from each label to the bottom.

    2) Hold down shift, since you might as well add the other constraint we’re going to use, namely, the “bottom space to bottom layout guide”.

    3) Select the “bottom space to bottom layout guide”, and “center horizontally in container”. Do this for all 3 labels.

    Hold down shift to add these two constraints for each label

    Basically, if we take the label whose coordinate we wish to determine and divide it by the total number of labels plus 1, then we have a number we can add to IB to get the dynamic location. I’m simplifying the formula, but you could use it for setting horizontal spacing or both vertical and horizontal at the same time. It’s super powerful!

    Here are our multipliers.

    Label1 = 1/4 = .25,

    Label2 = 2/4 = .5,

    Label3 = 3/4 = .75

    (Edit: @Rivera commented that you can simply use the ratios directly in the multiplier field, and xCode with do the math!)

    4) So, let’s select Label1 and select the bottom constraint. Like this:
    enter image description here

    5) Select the “Second Item” in the Attributes Inspector.

    6) From the drop down select “Reverse first and second item”.

    7) Zero out the constant and the wC hAny value. (You could add an offset here if you needed it).

    8) This is the critical part: In the multiplier field add our first multiplier 0.25.

    9) While you’re at it set the top “First item” to “CenterY” since we want to center it to the label’s y center. Here’s how all that should look.

    enter image description here

    10) Repeat this process for each label and plug in the relevant multiplier: 0.5 for Label2, and 0.75 for Label3. Here’s the final product in all orientations with all compact devices! Super simple. I’ve been looking at a lot of solutions involving reams of code, and spacers. This is far and away the best solution I’ve seen on the issue.

    Update: @kraftydevil adds that Bottom layout guide only appear in storyboards, not in xibs. Use ‘Bottom Space to Container’ in xibs. Good catch!

    enter image description here

    Very quick Interface Builder solution:

    For any number of views to be evenly spaced within a superview, simply give each an “Align Center X to superview” constraint for horizontal layout, or “Align Center Y superview” for vertical layout, and set the Multiplier to be N:p (NOTE: some have had better luck with p:N – see below)

    where

    N = total number of views, and

    p = position of the view including spaces

    First position is 1, then a space, making the next position 3, so p becomes a series [1,3,5,7,9,…]. Works for any number of views.

    So, if you have 3 views to space out, it looks like this:

    Illustration of how to evenly spread views in IB

    EDIT Note: The choice of N:p or p:N depends on the relation order of your alignment constraint. If “First Item” is Superview.Center, you may use p:N, while if Superview.Center is “Second Item”, you may use N:p. If in doubt, just try both out… 🙂

    I’ve been on a rollercoaster ride of loving autolayout and hating it. The key to loving it seems to be to accept the following:

    1. Interface builder’s editing and “helpful” auto-creation of constraints is near useless for all but the most trivial case
    2. Creating categories to simplify common operations is a life-saver since the code is so repetitive and verbose.

    That said, what you are attempting is not straightforward and would be difficult to achieve in interface builder. It is pretty simple to do in code. This code, in viewDidLoad, creates and positions three labels how you are asking for them:

    // Create three labels, turning off the default constraints applied to views created in code
    UILabel *label1 = [UILabel new];
    label1.translatesAutoresizingMaskIntoConstraints = NO;
    label1.text = @"Label 1";
    
    UILabel *label2 = [UILabel new];
    label2.translatesAutoresizingMaskIntoConstraints = NO;
    label2.text = @"Label 2";
    
    UILabel *label3 = [UILabel new];
    label3.translatesAutoresizingMaskIntoConstraints = NO;
    label3.text = @"Label 3";
    
    // Add them all to the view
    [self.view addSubview:label1];
    [self.view addSubview:label2];
    [self.view addSubview:label3];
    
    // Center them all horizontally
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
    
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
    
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
    
    // Center the middle one vertically
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];
    
    // Position the top one half way up
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:0.5 constant:0]];
    
    // Position the bottom one half way down
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:1.5 constant:0]];
    

    As I say, this code is much simplified with a couple of category methods in UIView, but for clarity I’ve done it the long way here.

    The category is here for those interested, and it has a method for evenly spacing an array of views along a particular axis.

    As of iOS 9, Apple has made this very easy with the (long-awaited) UIStackView. Just select the views you want to contain in the Interface Builder and choose Editor -> Embed In -> Stack view. Set the appropriate width/height/margin constraints for the stack view, and make sure to set the Distribution property to ‘Equal spacing’:

    Of course, if you need to support iOS 8 or lower, you’ll have to choose one of the other options.

    Most of these solutions depend on there being an odd number of items so that you can take the middle item and center it. What if you have an even number of items that you still want to be evenly distributed? Here’s a more general solution. This category will evenly distribute any number of items along either the vertical or horizontal axis.

    Example usage to vertically distribute 4 labels within their superview:

    [self.view addConstraints:
         [NSLayoutConstraint constraintsForEvenDistributionOfItems:@[label1, label2, label3, label4]
                                            relativeToCenterOfItem:self.view
                                                        vertically:YES]];
    

    NSLayoutConstraint+EvenDistribution.h

    @interface NSLayoutConstraint (EvenDistribution)
    
    /**
     * Returns constraints that will cause a set of views to be evenly distributed horizontally
     * or vertically relative to the center of another item. This is used to maintain an even
     * distribution of subviews even when the superview is resized.
     */
    + (NSArray *) constraintsForEvenDistributionOfItems:(NSArray *)views
                                 relativeToCenterOfItem:(id)toView
                                             vertically:(BOOL)vertically;
    
    @end
    

    NSLayoutConstraint+EvenDistribution.m

    @implementation NSLayoutConstraint (EvenDistribution)
    
    +(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                               relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
    {
        NSMutableArray *constraints = [NSMutableArray new];
        NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;
    
        for (NSUInteger i = 0; i < [views count]; i++) {
            id view = views[i];
            CGFloat multiplier = (2*i + 2) / (CGFloat)([views count] + 1);
            NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                          attribute:attr
                                                                          relatedBy:NSLayoutRelationEqual
                                                                             toItem:toView
                                                                          attribute:attr
                                                                         multiplier:multiplier
                                                                           constant:0];
            [constraints addObject:constraint];
        }
    
        return constraints;
    }
    
    @end
    

    Check out the open source library PureLayout. It offers a few API methods for distributing views, including variants where the spacing between each view is fixed (view size varies as needed), and where the size of each view is fixed (spacing between views varies as needed). Note that all of these are accomplished without the use of any “spacer views”.

    From NSArray+PureLayout.h:

    // NSArray+PureLayout.h
    
    // ...
    
    /** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
    - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                    alignedTo:(ALAttribute)alignment
                             withFixedSpacing:(CGFloat)spacing;
    
    /** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
    - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                    alignedTo:(ALAttribute)alignment
                                withFixedSize:(CGFloat)size;
    
    // ...
    

    Since it’s all open source, if you’re interested to see how this is achieved without spacer views just take a look at the implementation. (It depends on leveraging both the constant and multiplier for the constraints.)

    The correct and easiest way is to use Stack Views.

    1. Add your labels/views to the Stack View:

    enter image description here

    1. Select the Stack View and set Distribution to be Equal Spacing:

    enter image description here

    1. Add Spacing to nearest neighbor constraints to the Stack View and update frames:

    enter image description here

    1. Add Height constraints to all the labels:

    enter image description here

    1. Enjoy Preview:

    enter image description here

    I am having a similar problem and discovered this post. However, none of the currently provided answers solve the problem in the way you want. They don’t make the spacing equally, but rather distribute the center of the labels equally. It is important to understand that this is not the same. I’ve constructed a little diagram to illustrate this.

    View Spacing Illustration

    There are 3 views, all 20pt tall. Using any of the suggested methods equally distributes the centers of the views and give you the illustrated layout. Notice that the y-center of the views are spaced equally. However, the spacing between superview and top view is 15pt, while the spacing between the subviews is just 5pt. To have the views spaced equally these should both be 10pt, i.e. all blue arrows should be 10pt.

    Nevertheless, I haven’t come up with a good generic solution, yet. Currently my best idea is to insert “spacing views” between the subviews and setting the heights of the spacing views to be equal.

    I was able to solve this entirely in IB:

    1. Make constraints to align the center Y of each of your subviews to the bottom edge of the superview.
    2. Set the multiplier of each of these constraints to 1/2n, 3/2n, 5/2n, …, n-1/2n where n is the number of subviews you are distributing.

    So if you have three labels, set the multipliers to each of those constraints to 0.1666667, 0.5, 0.833333.

    I found a perfect and simple method. The auto layout does not allow you to resize the spaces equally, but it does allow you to resize views equally. Simply put some invisible views in between your fields and tell auto layout to keep them the same size. It works perfectly!

    Initial XIB

    Stretched XIB

    One thing of note though; when I reduced the size in the interface designer, sometimes it got confused and left a label where it was, and it had a conflict if the size was changed by an odd amount. Otherwise it worked perfectly.

    edit: I found that the conflict became a problem. Because of that, I took one of the spacing constraints, deleted it and replaced it with two constraints, a greater-than-or-equal and a less-than-or-equal. Both were the same size and had a much lower priority than the other constraints. The result was no further conflict.

    With labels this works fine at least:

    @"H:|-15-[first(==second)]-[second(==third)]-[third(==first)]-15-|

    If the first has the same width as the second, and second the third, and third the first, then they will all get the same width… You can do it both horizontally (H) and vertically (V).

    Building on Ben Dolman’s answer, this distributes the views more evenly (with padding, etc):

    +(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                               relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
    {
        NSMutableArray *constraints = [NSMutableArray new];
        NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;
    
        CGFloat min = 0.25;
        CGFloat max = 1.75;
        CGFloat d = (max-min) / ([views count] - 1);
        for (NSUInteger i = 0; i < [views count]; i++) {
            id view = views[i];
            CGFloat multiplier = i * d + min;
            NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                          attribute:attr
                                                                          relatedBy:NSLayoutRelationEqual
                                                                             toItem:toView
                                                                          attribute:attr
                                                                         multiplier:multiplier
                                                                           constant:0];
            [constraints addObject:constraint];
        }
    
        return constraints;
    }
    

    I know it’s been a while since the first answer, but I just came across the very same problem and I want to share my solution. For generations to come…

    I set my views on viewDidLoad:

    - (void)viewDidLoad {
    
        [super viewDidLoad];
    
        cancelButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
        cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
        [cancelButton setTitle:@"Cancel" forState:UIControlStateNormal];
        [self.view addSubview:cancelButton];
    
        middleButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
        middleButton.translatesAutoresizingMaskIntoConstraints = NO;
        [middleButton setTitle:@"Middle" forState:UIControlStateNormal];
        [self.view addSubview:middleButton];
    
        nextButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
        nextButton.translatesAutoresizingMaskIntoConstraints = NO;
        [nextButton setTitle:@"Next" forState:UIControlStateNormal];
        [self.view addSubview:nextButton];
    
    
        [self.view setNeedsUpdateConstraints];
    
    }
    

    And then, on updateViewConstrains, first I delete all constrains, then I create the views dictionary and then I calculate the space to be used between views. After that, I just use the Visual Language Format to set the constraints:

    - (void)updateViewConstraints {
    
    
        [super updateViewConstraints];
    
        [self.view removeConstraints:self.view.constraints];
    
        NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(cancelButton, nextButton, middleButton);
    
        float distance=(self.view.bounds.size.width-cancelButton.intrinsicContentSize.width-nextButton.intrinsicContentSize.width-middleButton.intrinsicContentSize.width-20-20)/  ([viewsDictionary count]-1);  // 2 times 20 counts for the left & rigth margins
        NSNumber *distancies=[NSNumber numberWithFloat:distance];
    
    //    NSLog(@"Distancies: %@", distancies);
    //    
    //    NSLog(@"View Width: %f", self.view.bounds.size.width);
    //    NSLog(@"Cancel Width: %f", cancelButton.intrinsicContentSize.width);
    //    NSLog(@"Middle Width: %f", middleButton.intrinsicContentSize.width);
    //    NSLog(@"Next Width: %f", nextButton.intrinsicContentSize.width);
    
    
    
        NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-[cancelButton]-dis-[middleButton]-dis-[nextButton]-|"
                                                                       options:NSLayoutFormatAlignAllBaseline
                                                                       metrics:@{@"dis":distancies}
                                                                         views:viewsDictionary];
    
    
        [self.view addConstraints:constraints];
    
    
    
        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[nextButton]-|"
                                                              options:0
                                                              metrics:nil
                                                                views:viewsDictionary];
        [self.view addConstraints:constraints];
    
    
    
    }
    

    The good thing about this method is that you have to do very little math. I’m not saying this is the perfect solution, but I works for the layout I was trying to achieve.

    I hope it helps.

    I have made a function that might help.
    This usage example :

     [self.view addConstraints: [NSLayoutConstraint fluidConstraintWithItems:NSDictionaryOfVariableBindings(button1, button2, button3)
                                                                    asString:@[@"button1", @"button2", @"button3"]
                                                                   alignAxis:@"V"
                                                              verticalMargin:100
                                                            horizontalMargin:50
                                                                 innerMargin:25]];
    

    will cause that vertical distribution (sorry don’t have the 10 reputation to embed images). And if you change the axis and some margin values :

    alignAxis:@"H"
    verticalMargin:120
    horizontalMargin:20
    innerMargin:10
    

    You’ll get that horizontal distribution.

    I’m newbie in iOS but voilà !

    EvenDistribution.h

    @interface NSLayoutConstraint (EvenDistribution)
    
    /**
     * Returns constraints that will cause a set of subviews
     * to be evenly distributed along an axis.
     */
    + (NSArray *)  fluidConstraintWithItems:(NSDictionary *) views
                                   asString:(NSArray *) stringViews
                                  alignAxis:(NSString *) axis
                             verticalMargin:(NSUInteger) vMargin
                           horizontalMargin:(NSUInteger) hMargin
                                innerMargin:(NSUInteger) inner;
    @end
    

    EvenDistribution.m

    #import "EvenDistribution.h"
    
    @implementation NSLayoutConstraint (EvenDistribution)
    
    + (NSArray *) fluidConstraintWithItems:(NSDictionary *) dictViews
                                  asString:(NSArray *) stringViews
                                 alignAxis:(NSString *) axis
                            verticalMargin:(NSUInteger) vMargin
                          horizontalMargin:(NSUInteger) hMargin
                               innerMargin:(NSUInteger) iMargin
    
    {
        NSMutableArray *constraints = [NSMutableArray arrayWithCapacity: dictViews.count];
        NSMutableString *globalFormat = [NSMutableString stringWithFormat:@"%@:|-%d-",
                                         axis,
                                         [axis isEqualToString:@"V"] ? vMargin : hMargin
                                         ];
    
    
    
            for (NSUInteger i = 0; i < dictViews.count; i++) {
    
                if (i == 0)
                    [globalFormat appendString:[NSString stringWithFormat: @"[%@]-%d-", stringViews[i], iMargin]];
                else if(i == dictViews.count - 1)
                    [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-", stringViews[i], stringViews[i-1]]];
                else
                   [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-%d-", stringViews[i], stringViews[i-1], iMargin]];
    
                NSString *localFormat = [NSString stringWithFormat: @"%@:|-%d-[%@]-%d-|",
                                         [axis isEqualToString:@"V"] ? @"H" : @"V",
                                         [axis isEqualToString:@"V"] ? hMargin : vMargin,
                                         stringViews[i],
                                         [axis isEqualToString:@"V"] ? hMargin : vMargin];
    
                [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:localFormat
                                                                                         options:0
                                                                                         metrics:nil
                                                                                           views:dictViews]];
    
    
        }
        [globalFormat appendString:[NSString stringWithFormat:@"%d-|",
                                    [axis isEqualToString:@"V"] ? vMargin : hMargin
                                    ]];
    
        [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:globalFormat
                                                                                 options:0
                                                                                 metrics:nil
                                                                                   views:dictViews]];
    
        return constraints;
    
    }
    
    @end
    

    Here is a solution that will vertically center any number of subviews, even if they have unique sizes. What you want to do is make a mid-level container, center that in the superview, then put all the subviews in the container and arrange them with respect to one another. But crucially you also need to constrain them to the top and bottom of the container, so the container can be correctly sized and centered in the superview. By figuring the correct height from its subviews, the container can be vertically centered.

    In this example, self is the superview in which you are centering all the subviews.

    NSArray *subviews = @[ (your subviews in top-to-bottom order) ];
    
    UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
    container.translatesAutoresizingMaskIntoConstraints = NO;
    for (UIView *subview in subviews) {
        subview.translatesAutoresizingMaskIntoConstraints = NO;
        [container addSubview:subview];
    }
    [self addSubview:container];
    
    [self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
                                                        toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]];
    [self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
                                                        toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]];
    [self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual
                                                        toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]];
    
    if (0 < subviews.count) {
        UIView *firstSubview = subviews[0];
        [container addConstraint:[NSLayoutConstraint constraintWithItem:firstSubview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                                 toItem:container attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
        UIView *lastSubview = subviews.lastObject;
        [container addConstraint:[NSLayoutConstraint constraintWithItem:lastSubview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual
                                                                 toItem:container attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]];
    
        UIView *subviewAbove = nil;
        for (UIView *subview in subviews) {
            [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
                                                                     toItem:container attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]];
            if (subviewAbove) {
                [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                                         toItem:subviewAbove attribute:NSLayoutAttributeBottom multiplier:1.0f constant:10.0f]];
            }
            subviewAbove = subview;
        }
    }
    

    I just solved my problem using the multiplier feature. I’m not sure it works for all cases, but for me it worked perfectly. I’m on Xcode 6.3 FYI.

    What I ended up doing was:

    1) First getting my buttons positioned on a 320px width screen distributed the way I wanted it to look on a 320px device.

    step 1: getting buttons positioned

    2) Then I added a leading Space constraint to superview on all of my buttons.

    step 2: add leading space constraints

    3) Then I modified the properties of the leading space so that the constant was 0 and the multiplier is the x offset divided by width of the screen (e.g. my first button was 8px from left edge so I set my multiplier to 8/320)

    4) Then the important step here is to change the second Item in the constraint relation to be the superview.Trailing instead of superview.leading. This is key because superview.Leading is 0 and trailing in my case is 320, so 8/320 is 8 px on a 320px device, then when the superview’s width changes to 640 or whatever, the views all move at a ratio relative to width of the 320px screen size. The math here is much simpler to understand.

    step 3 & 4: change multiplier to xPos/screenWidth and set second item to .Trailing

    Many answers are not correct, but get many counts. Here I just write a solution programmatically, the three views are horizontal align, without using spacer views, but it only work when the widths of labels are known when used in storyboard.

    NSDictionary *views = NSDictionaryOfVariableBindings(_redView, _yellowView, _blueView);
    
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:views]];
    
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_redView(60)]" options:0 metrics:nil views:views]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_redView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
    
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_redView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:0.5 constant:0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_blueView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:1.5 constant:40]];
    

    Another approach might be to have the top and bottom labels have constraints relative to the view top and bottom, respectively, and have the middle view have top and bottom constraints relative to the first and third view, respectively.

    Note that you have more control over constraints than it might seem by dragging views close to one another until guiding dashed lines appear – these indicate constraints between the two objects that will be formed instead of between the object and the superview.

    In this case you would then want to alter the constraints to be “Greater than or equal to” the desired value, instead of “equal to” to allow them to resize. Not sure if this will do exactly what you want.

    Very easy way to solve this in InterfaceBuilder:

    Set the centered label (label2) to “Horizontal Center in Container” and “Vertical Center in Container”

    Select the centered label and the top label (label1 + label2) and add TWO constraints for Vertical Spacing. One with Greater Than or Equal the min spacing. One with Less Than or Equal the max spacing.

    The same for the centered label and the bottom label (label2 + label3).

    Additionally you could also add two constraints to label1 – Top Space To SuperView and two constraints to label2 – Bottom Space To SuperView.

    The result will be that all 4 spacings will change their sizes equally.

    Yes, you can do this solely in interface builder and without writing code – the one caveat is that you are resizing the label instead of distributing whitespace. In this case, align Label 2’s X and Y to the superview so it is fixed in the center. Then set label 1’s vertical space to the superview and to label 2 to the standard, repeat for label 3. After setting label 2 the easiest way to set label 1 and 3 is to resize them until they snap.

    Here is the horizontal display, note that the vertical space between label 1 and 2 is set to standard:horizontal display

    And here is the portrait version:enter image description here

    I realize they are not absolutely 100% equally spaced between the baselines due to the difference between the standard space between labels and the standard space to the superview. If that bothers you, set the size to 0 instead of standard

    I set a width value just for the first item (>= a width) and a minimum distance between each item (>= a distance). Then I use Ctrl to drag second, third… item on the first one to chain dependencies among the items.

    enter image description here

    Late to the party but I have a working solution for creating a menu horizontally with spacing. It can be easily done using == in NSLayoutConstraint

    const float MENU_HEIGHT = 40;
    
    - (UIView*) createMenuWithLabels: (NSArray *) labels
        // labels is NSArray of NSString
        UIView * backgroundView = [[UIView alloc]init];
        backgroundView.translatesAutoresizingMaskIntoConstraints = false;
    
        NSMutableDictionary * views = [[NSMutableDictionary alloc] init];
        NSMutableString * format = [[NSMutableString alloc] initWithString: @"H:|"];
        NSString * firstLabelKey;
    
        for(NSString * str in labels)
        {
            UILabel * label = [[UILabel alloc] init];
            label.translatesAutoresizingMaskIntoConstraints = false;
            label.text = str;
            label.textAlignment = NSTextAlignmentCenter;
            label.textColor = [UIColor whiteColor];
            [backgroundView addSubview: label];
            [label fixHeightToTopBounds: MENU_HEIGHT-2];
            [backgroundView addConstraints: [label fixHeightToTopBounds: MENU_HEIGHT]];
            NSString * key = [self camelCaseFromString: str];
            [views setObject: label forKey: key];
            if(firstLabelKey == nil)
            {
                [format appendString: [NSString stringWithFormat: @"[%@]", key]];
                firstLabelKey = key;
            }
            else
            {
                [format appendString: [NSString stringWithFormat: @"[%@(==%@)]", key, firstLabelKey]];
            }
        }
    
        [format appendString: @"|"];
    
        NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat: (NSString *) format
                                                                                   options: 0
                                                                                   metrics: nil
                                                                                     views: (NSDictionary *) views];
        [backgroundView addConstraints: constraints];
        return backgroundView;
    }
    

    Here is yet another answer. I was answering a similar question and saw link referenced to this question. I didnt see any answer similar to mine. So, I thought of writing it here.

      class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = UIColor.whiteColor()
            setupViews()
        }
    
        var constraints: [NSLayoutConstraint] = []
    
        func setupViews() {
    
            let container1 = createButtonContainer(withButtonTitle: "Button 1")
            let container2 = createButtonContainer(withButtonTitle: "Button 2")
            let container3 = createButtonContainer(withButtonTitle: "Button 3")
            let container4 = createButtonContainer(withButtonTitle: "Button 4")
    
            view.addSubview(container1)
            view.addSubview(container2)
            view.addSubview(container3)
            view.addSubview(container4)
    
            [
    
                // left right alignment
                container1.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
                container1.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20),
                container2.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
                container2.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
                container3.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
                container3.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
                container4.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
                container4.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
    
    
                // place containers one after another vertically
                container1.topAnchor.constraintEqualToAnchor(view.topAnchor),
                container2.topAnchor.constraintEqualToAnchor(container1.bottomAnchor),
                container3.topAnchor.constraintEqualToAnchor(container2.bottomAnchor),
                container4.topAnchor.constraintEqualToAnchor(container3.bottomAnchor),
                container4.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
    
    
                // container height constraints
                container2.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
                container3.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
                container4.heightAnchor.constraintEqualToAnchor(container1.heightAnchor)
                ]
                .forEach { $0.active = true }
        }
    
    
        func createButtonContainer(withButtonTitle title: String) -> UIView {
            let view = UIView(frame: .zero)
            view.translatesAutoresizingMaskIntoConstraints = false
    
            let button = UIButton(type: .System)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.setTitle(title, forState: .Normal)
            view.addSubview(button)
    
            [button.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
                button.leftAnchor.constraintEqualToAnchor(view.leftAnchor),
                button.rightAnchor.constraintEqualToAnchor(view.rightAnchor)].forEach { $0.active = true }
    
            return view
        }
    }
    

    enter image description here

    And again, this can be done quite easily with iOS9 UIStackViews as well.

    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = UIColor.greenColor()
            setupViews()
        }
    
        var constraints: [NSLayoutConstraint] = []
    
        func setupViews() {
    
            let container1 = createButtonContainer(withButtonTitle: "Button 1")
            let container2 = createButtonContainer(withButtonTitle: "Button 2")
            let container3 = createButtonContainer(withButtonTitle: "Button 3")
            let container4 = createButtonContainer(withButtonTitle: "Button 4")
    
            let stackView = UIStackView(arrangedSubviews: [container1, container2, container3, container4])
            stackView.translatesAutoresizingMaskIntoConstraints = false
            stackView.axis = .Vertical
            stackView.distribution = .FillEqually
            view.addSubview(stackView)
    
            [stackView.topAnchor.constraintEqualToAnchor(view.topAnchor),
                stackView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
                stackView.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
                stackView.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20)].forEach { $0.active = true }
        }
    
    
        func createButtonContainer(withButtonTitle title: String) -> UIView {
            let button = UIButton(type: .Custom)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.backgroundColor = UIColor.redColor()
            button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
            button.setTitle(title, forState: .Normal)
            let buttonContainer = UIStackView(arrangedSubviews: [button])
            buttonContainer.distribution = .EqualCentering
            buttonContainer.alignment = .Center
            buttonContainer.translatesAutoresizingMaskIntoConstraints = false
            return buttonContainer
        }
    }
    

    Notice that it is exact same approach as above. It adds four container views which are filled equally and a view is added to each stack view which is aligned in center. But, this version of UIStackView reduces some code and looks nice.

    swift 3 version

    let _redView = UIView()
            _redView.backgroundColor = UIColor.red
            _redView.translatesAutoresizingMaskIntoConstraints = false
    
            let _yellowView = UIView()
            _yellowView.backgroundColor = UIColor.yellow
            _yellowView.translatesAutoresizingMaskIntoConstraints = false
    
            let _blueView = UIView()
            _blueView.backgroundColor = UIColor.blue
            _blueView.translatesAutoresizingMaskIntoConstraints = false
    
            self.view.addSubview(_redView)
            self.view.addSubview(_yellowView)
            self.view.addSubview(_blueView)
    
            var views = ["_redView": _redView, "_yellowView": _yellowView, "_blueView":_blueView]
    
            var nslayoutConstraint_H = NSLayoutConstraint.constraints(withVisualFormat: "|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|", options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views)
            self.view.addConstraints(nslayoutConstraint_H)
    
            var nslayoutConstraint_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[_redView(60)]", options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: views)
            self.view.addConstraints(nslayoutConstraint_V)
    
    
            let constraint_red = NSLayoutConstraint.init(item: self.view, attribute: .centerY, relatedBy: .equal, toItem: _redView, attribute: .centerY, multiplier: 1, constant: 0)
            self.view.addConstraint(constraint_red)
    
            let constraint_yellow = NSLayoutConstraint.init(item: self.view, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .centerX, multiplier: 1, constant: 0)
            self.view.addConstraint(constraint_yellow)
    
            let constraint_yellow1 = NSLayoutConstraint.init(item: _redView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 0.5, constant: 0)
            self.view.addConstraint(constraint_yellow1)
    
            let constraint_yellow2 = NSLayoutConstraint.init(item: _blueView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 1.5, constant: 40)
            self.view.addConstraint(constraint_yellow2)
    

    Why dont you just create a tableView and make isScrollEnabled = false