2
votes

I'm learning auto layout and I'd like to setup a set of buttons to be vertically stacked and evenly spaced. I'd also like the buttons pinned to the bottom of the view. What's a good way to setup these constraints with VFL? The button list will be passed in as an array of UIButtons.

NSArray *buttons = [button1, button2, button3, button4, ...]
NSMutableArray *allConstraints = [NSMutableArray array]
UIButton *previousButton;

for (UIButton button in buttons) {
    // Buttons take up full width 
    NSArray *constraints = [NSLayoutConstraint
            constraintsWithVisualFormat:@"H:|[button]|"
                                options:0
                                metrics:nil
                                  views:NSDictionaryOfVariableBindings(button);];
    [allConstraints addObjectsFromArray:constraints];

    constraints = [NSLayoutConstraint
            constraintsWithVisualFormat:@"V:|[button]|"
                                options:0
                                metrics:nil
                                  views:NSDictionaryOfVariableBindings(button);];
    [allConstraints addObjectsFromArray:constraints];

    if (!previousButton) {
        NSDictionary *metrics = @{@"padding" : @(10)};

        // Make buttons height
        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[-(padding)-previousButton(==button)]"
                                                              options:0
                                                              metrics:metrics
                                                                views:NSDictionaryOfVariableBindings(previousButton, button)];
        [allConstraints addObjectsFromArray:constraints];
    }
    previousButton = button;
}

[self.view addConstraints:allConstraints]

This doesn't achieve what I need as the buttons don't get pinned to the bottom of the view.

2

2 Answers

5
votes

I would do it in a somewhat different way. Rather than building up the constraints inside a loop, I would build the format string in a loop.

-(void)addButtonsWithConstraints:(NSArray *) buttons {
    NSMutableDictionary *views = [NSMutableDictionary new];
    for (int i = 0; i<buttons.count; i++) {
        [buttons[i] setTranslatesAutoresizingMaskIntoConstraints: NO];
        [self.view addSubview:buttons[i]];
        [views setObject:buttons[i] forKey:[NSString stringWithFormat:@"button%d",i]];
    }

    NSMutableString *formatString = [@"V:" mutableCopy];
    for (int i = 0; i<buttons.count-1; i++) {
        [formatString appendFormat:@"[button%d]-10-", i];
    }
    [formatString appendFormat:@"[button%lu]|", buttons.count - 1]; // pins the last button to the bottom of the view
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:formatString options:NSLayoutFormatAlignAllLeft | NSLayoutFormatAlignAllRight metrics:nil views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[button0]|" options:0 metrics:nil views:views]];
}

The last line sets button0 to the full width of the view, and the format options in the previous line make all the buttons align their left and right edges.

1
votes

Hi this might help you out

NSArray *buttons = @[button1, button2, button3, button4, button5];
NSMutableArray *allConstraints = [NSMutableArray array];
UIButton *previousButton;

for (UIButton *button in buttons) {
    [button setTranslatesAutoresizingMaskIntoConstraints:NO];
    // Buttons take up full width
    NSArray *constraints = [NSLayoutConstraint
                            constraintsWithVisualFormat:@"H:|[button]|"
                            options:0
                            metrics:nil
                            views:NSDictionaryOfVariableBindings(button)];
    [allConstraints addObjectsFromArray:constraints];
    if (!previousButton) {
    constraints = [NSLayoutConstraint
                   constraintsWithVisualFormat:@"V:|->=10-[button(65)]"
                   options: 0
                   metrics:nil
                   views:NSDictionaryOfVariableBindings(button)];
                [allConstraints addObjectsFromArray:constraints];
    }
    if (previousButton) {
        NSDictionary *metrics = @{@"padding" : @(10)};

        // Make buttons height
        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[previousButton]-(20)-[button(65)]"
                                                              options:0
                                                              metrics:metrics
                                                                views:NSDictionaryOfVariableBindings(previousButton, button)];
        [allConstraints addObjectsFromArray:constraints];
    }
    previousButton = button;
}
NSArray *constraints = [NSLayoutConstraint
                        constraintsWithVisualFormat:@"V:[previousButton]-10-|"
                        options:0
                        metrics:nil
                        views:NSDictionaryOfVariableBindings(previousButton)];
[allConstraints addObjectsFromArray:constraints];
[self.view addConstraints:allConstraints]